You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

rtc_entropy.c 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199
  1. /*
  2. * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
  3. *
  4. * This program is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU General Public License as
  6. * published by the Free Software Foundation; either version 2 of the
  7. * License, or any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful, but
  10. * WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, write to the Free Software
  16. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  17. * 02110-1301, USA.
  18. */
  19. FILE_LICENCE ( GPL2_OR_LATER );
  20. /** @file
  21. *
  22. * RTC-based entropy source
  23. *
  24. */
  25. #include <stdint.h>
  26. #include <string.h>
  27. #include <biosint.h>
  28. #include <pic8259.h>
  29. #include <rtc.h>
  30. #include <ipxe/entropy.h>
  31. /** RTC "interrupt triggered" flag */
  32. static uint8_t __text16 ( rtc_flag );
  33. #define rtc_flag __use_text16 ( rtc_flag )
  34. /** RTC interrupt handler */
  35. extern void rtc_isr ( void );
  36. /** Previous RTC interrupt handler */
  37. static struct segoff rtc_old_handler;
  38. /**
  39. * Hook RTC interrupt handler
  40. *
  41. */
  42. static void rtc_hook_isr ( void ) {
  43. /* RTC interrupt handler */
  44. __asm__ __volatile__ (
  45. TEXT16_CODE ( "\nrtc_isr:\n\t"
  46. /* Preserve registers */
  47. "pushw %%ax\n\t"
  48. /* Set "interrupt triggered" flag */
  49. "cs movb $0x01, %c0\n\t"
  50. /* Read RTC status register C to
  51. * acknowledge interrupt
  52. */
  53. "movb %3, %%al\n\t"
  54. "outb %%al, %1\n\t"
  55. "inb %2\n\t"
  56. /* Send EOI */
  57. "movb $0x20, %%al\n\t"
  58. "outb %%al, $0xa0\n\t"
  59. "outb %%al, $0x20\n\t"
  60. /* Restore registers and return */
  61. "popw %%ax\n\t"
  62. "iret\n\t" )
  63. :
  64. : "p" ( __from_text16 ( &rtc_flag ) ),
  65. "i" ( CMOS_ADDRESS ), "i" ( CMOS_DATA ),
  66. "i" ( RTC_STATUS_C ) );
  67. hook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
  68. &rtc_old_handler );
  69. }
  70. /**
  71. * Unhook RTC interrupt handler
  72. *
  73. */
  74. static void rtc_unhook_isr ( void ) {
  75. int rc;
  76. rc = unhook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
  77. &rtc_old_handler );
  78. assert ( rc == 0 ); /* Should always be able to unhook */
  79. }
  80. /**
  81. * Enable RTC interrupts
  82. *
  83. */
  84. static void rtc_enable_int ( void ) {
  85. uint8_t status_b;
  86. /* Set Periodic Interrupt Enable bit in status register B */
  87. outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
  88. status_b = inb ( CMOS_DATA );
  89. outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
  90. outb ( ( status_b | RTC_STATUS_B_PIE ), CMOS_DATA );
  91. /* Re-enable NMI and reset to default address */
  92. outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
  93. inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
  94. }
  95. /**
  96. * Disable RTC interrupts
  97. *
  98. */
  99. static void rtc_disable_int ( void ) {
  100. uint8_t status_b;
  101. /* Clear Periodic Interrupt Enable bit in status register B */
  102. outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
  103. status_b = inb ( CMOS_DATA );
  104. outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
  105. outb ( ( status_b & ~RTC_STATUS_B_PIE ), CMOS_DATA );
  106. /* Re-enable NMI and reset to default address */
  107. outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
  108. inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
  109. }
  110. /**
  111. * Enable entropy gathering
  112. *
  113. * @ret rc Return status code
  114. */
  115. static int rtc_entropy_enable ( void ) {
  116. rtc_hook_isr();
  117. enable_irq ( RTC_IRQ );
  118. rtc_enable_int();
  119. return 0;
  120. }
  121. /**
  122. * Disable entropy gathering
  123. *
  124. */
  125. static void rtc_entropy_disable ( void ) {
  126. rtc_disable_int();
  127. disable_irq ( RTC_IRQ );
  128. rtc_unhook_isr();
  129. }
  130. /**
  131. * Measure a single RTC tick
  132. *
  133. * @ret delta Length of RTC tick (in TSC units)
  134. */
  135. uint8_t rtc_sample ( void ) {
  136. uint32_t before;
  137. uint32_t after;
  138. uint32_t temp;
  139. __asm__ __volatile__ (
  140. REAL_CODE ( /* Enable interrupts */
  141. "sti\n\t"
  142. /* Wait for RTC interrupt */
  143. "cs movb %b2, %c4\n\t"
  144. "\n1:\n\t"
  145. "cs xchgb %b2, %c4\n\t" /* Serialize */
  146. "testb %b2, %b2\n\t"
  147. "jz 1b\n\t"
  148. /* Read "before" TSC */
  149. "rdtsc\n\t"
  150. /* Store "before" TSC on stack */
  151. "pushl %0\n\t"
  152. /* Wait for another RTC interrupt */
  153. "xorb %b2, %b2\n\t"
  154. "cs movb %b2, %c4\n\t"
  155. "\n1:\n\t"
  156. "cs xchgb %b2, %c4\n\t" /* Serialize */
  157. "testb %b2, %b2\n\t"
  158. "jz 1b\n\t"
  159. /* Read "after" TSC */
  160. "rdtsc\n\t"
  161. /* Retrieve "before" TSC on stack */
  162. "popl %1\n\t"
  163. /* Disable interrupts */
  164. "cli\n\t"
  165. )
  166. : "=a" ( after ), "=d" ( before ), "=q" ( temp )
  167. : "2" ( 0 ), "p" ( __from_text16 ( &rtc_flag ) ) );
  168. return ( after - before );
  169. }
  170. PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample );
  171. PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable );
  172. PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable );
  173. PROVIDE_ENTROPY_INLINE ( rtc, get_noise );