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.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  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. * You can also choose to distribute this program under the terms of
  20. * the Unmodified Binary Distribution Licence (as given in the file
  21. * COPYING.UBDL), provided that you have satisfied its requirements.
  22. */
  23. FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
  24. /** @file
  25. *
  26. * RTC-based entropy source
  27. *
  28. */
  29. #include <stdint.h>
  30. #include <string.h>
  31. #include <biosint.h>
  32. #include <pic8259.h>
  33. #include <rtc.h>
  34. #include <ipxe/entropy.h>
  35. /** RTC "interrupt triggered" flag */
  36. static uint8_t __text16 ( rtc_flag );
  37. #define rtc_flag __use_text16 ( rtc_flag )
  38. /** RTC interrupt handler */
  39. extern void rtc_isr ( void );
  40. /** Previous RTC interrupt handler */
  41. static struct segoff rtc_old_handler;
  42. /**
  43. * Hook RTC interrupt handler
  44. *
  45. */
  46. static void rtc_hook_isr ( void ) {
  47. /* RTC interrupt handler */
  48. __asm__ __volatile__ (
  49. TEXT16_CODE ( "\nrtc_isr:\n\t"
  50. /* Preserve registers */
  51. "pushw %%ax\n\t"
  52. /* Set "interrupt triggered" flag */
  53. "cs movb $0x01, %c0\n\t"
  54. /* Read RTC status register C to
  55. * acknowledge interrupt
  56. */
  57. "movb %3, %%al\n\t"
  58. "outb %%al, %1\n\t"
  59. "inb %2\n\t"
  60. /* Send EOI */
  61. "movb $0x20, %%al\n\t"
  62. "outb %%al, $0xa0\n\t"
  63. "outb %%al, $0x20\n\t"
  64. /* Restore registers and return */
  65. "popw %%ax\n\t"
  66. "iret\n\t" )
  67. :
  68. : "p" ( __from_text16 ( &rtc_flag ) ),
  69. "i" ( CMOS_ADDRESS ), "i" ( CMOS_DATA ),
  70. "i" ( RTC_STATUS_C ) );
  71. hook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
  72. &rtc_old_handler );
  73. }
  74. /**
  75. * Unhook RTC interrupt handler
  76. *
  77. */
  78. static void rtc_unhook_isr ( void ) {
  79. int rc;
  80. rc = unhook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
  81. &rtc_old_handler );
  82. assert ( rc == 0 ); /* Should always be able to unhook */
  83. }
  84. /**
  85. * Enable RTC interrupts
  86. *
  87. */
  88. static void rtc_enable_int ( void ) {
  89. uint8_t status_b;
  90. /* Set Periodic Interrupt Enable bit in status register B */
  91. outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
  92. status_b = inb ( CMOS_DATA );
  93. outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
  94. outb ( ( status_b | RTC_STATUS_B_PIE ), CMOS_DATA );
  95. /* Re-enable NMI and reset to default address */
  96. outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
  97. inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
  98. }
  99. /**
  100. * Disable RTC interrupts
  101. *
  102. */
  103. static void rtc_disable_int ( void ) {
  104. uint8_t status_b;
  105. /* Clear Periodic Interrupt Enable bit in status register B */
  106. outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
  107. status_b = inb ( CMOS_DATA );
  108. outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
  109. outb ( ( status_b & ~RTC_STATUS_B_PIE ), CMOS_DATA );
  110. /* Re-enable NMI and reset to default address */
  111. outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
  112. inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
  113. }
  114. /**
  115. * Enable entropy gathering
  116. *
  117. * @ret rc Return status code
  118. */
  119. static int rtc_entropy_enable ( void ) {
  120. rtc_hook_isr();
  121. enable_irq ( RTC_IRQ );
  122. rtc_enable_int();
  123. return 0;
  124. }
  125. /**
  126. * Disable entropy gathering
  127. *
  128. */
  129. static void rtc_entropy_disable ( void ) {
  130. rtc_disable_int();
  131. disable_irq ( RTC_IRQ );
  132. rtc_unhook_isr();
  133. }
  134. /**
  135. * Measure a single RTC tick
  136. *
  137. * @ret delta Length of RTC tick (in TSC units)
  138. */
  139. uint8_t rtc_sample ( void ) {
  140. uint32_t before;
  141. uint32_t after;
  142. uint32_t temp;
  143. __asm__ __volatile__ (
  144. REAL_CODE ( /* Enable interrupts */
  145. "sti\n\t"
  146. /* Wait for RTC interrupt */
  147. "cs movb %b2, %c4\n\t"
  148. "\n1:\n\t"
  149. "cs xchgb %b2, %c4\n\t" /* Serialize */
  150. "testb %b2, %b2\n\t"
  151. "jz 1b\n\t"
  152. /* Read "before" TSC */
  153. "rdtsc\n\t"
  154. /* Store "before" TSC on stack */
  155. "pushl %0\n\t"
  156. /* Wait for another RTC interrupt */
  157. "xorb %b2, %b2\n\t"
  158. "cs movb %b2, %c4\n\t"
  159. "\n1:\n\t"
  160. "cs xchgb %b2, %c4\n\t" /* Serialize */
  161. "testb %b2, %b2\n\t"
  162. "jz 1b\n\t"
  163. /* Read "after" TSC */
  164. "rdtsc\n\t"
  165. /* Retrieve "before" TSC on stack */
  166. "popl %1\n\t"
  167. /* Disable interrupts */
  168. "cli\n\t"
  169. )
  170. : "=a" ( after ), "=d" ( before ), "=q" ( temp )
  171. : "2" ( 0 ), "p" ( __from_text16 ( &rtc_flag ) ) );
  172. return ( after - before );
  173. }
  174. PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample );
  175. PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable );
  176. PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable );
  177. PROVIDE_ENTROPY_INLINE ( rtc, get_noise );