2 * Copyright (C) 2012 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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
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.
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
28 * RTC-based entropy source
37 #include <ipxe/entropy.h>
39 /** RTC "interrupt triggered" flag */
40 static uint8_t __text16 ( rtc_flag );
41 #define rtc_flag __use_text16 ( rtc_flag )
43 /** RTC interrupt handler */
44 extern void rtc_isr ( void );
46 /** Previous RTC interrupt handler */
47 static struct segoff rtc_old_handler;
50 * Hook RTC interrupt handler
53 static void rtc_hook_isr ( void ) {
55 /* RTC interrupt handler */
56 __asm__ __volatile__ (
57 TEXT16_CODE ( "\nrtc_isr:\n\t"
58 /* Preserve registers */
60 /* Set "interrupt triggered" flag */
61 "cs movb $0x01, %c0\n\t"
62 /* Read RTC status register C to
63 * acknowledge interrupt
69 "movb $0x20, %%al\n\t"
70 "outb %%al, $0xa0\n\t"
71 "outb %%al, $0x20\n\t"
72 /* Restore registers and return */
76 : "p" ( __from_text16 ( &rtc_flag ) ),
77 "i" ( CMOS_ADDRESS ), "i" ( CMOS_DATA ),
78 "i" ( RTC_STATUS_C ) );
80 hook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
85 * Unhook RTC interrupt handler
88 static void rtc_unhook_isr ( void ) {
91 rc = unhook_bios_interrupt ( RTC_INT, ( unsigned int ) rtc_isr,
93 assert ( rc == 0 ); /* Should always be able to unhook */
97 * Enable RTC interrupts
100 static void rtc_enable_int ( void ) {
103 /* Set Periodic Interrupt Enable bit in status register B */
104 outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
105 status_b = inb ( CMOS_DATA );
106 outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
107 outb ( ( status_b | RTC_STATUS_B_PIE ), CMOS_DATA );
109 /* Re-enable NMI and reset to default address */
110 outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
111 inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
115 * Disable RTC interrupts
118 static void rtc_disable_int ( void ) {
121 /* Clear Periodic Interrupt Enable bit in status register B */
122 outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
123 status_b = inb ( CMOS_DATA );
124 outb ( ( RTC_STATUS_B | CMOS_DISABLE_NMI ), CMOS_ADDRESS );
125 outb ( ( status_b & ~RTC_STATUS_B_PIE ), CMOS_DATA );
127 /* Re-enable NMI and reset to default address */
128 outb ( CMOS_DEFAULT_ADDRESS, CMOS_ADDRESS );
129 inb ( CMOS_DATA ); /* Discard; may be needed on some platforms */
133 * Enable entropy gathering
135 * @ret rc Return status code
137 static int rtc_entropy_enable ( void ) {
140 enable_irq ( RTC_IRQ );
147 * Disable entropy gathering
150 static void rtc_entropy_disable ( void ) {
153 disable_irq ( RTC_IRQ );
158 * Measure a single RTC tick
160 * @ret delta Length of RTC tick (in TSC units)
162 uint8_t rtc_sample ( void ) {
167 __asm__ __volatile__ (
168 REAL_CODE ( /* Enable interrupts */
170 /* Wait for RTC interrupt */
171 "cs movb %b2, %c4\n\t"
173 "cs xchgb %b2, %c4\n\t" /* Serialize */
176 /* Read "before" TSC */
178 /* Store "before" TSC on stack */
180 /* Wait for another RTC interrupt */
182 "cs movb %b2, %c4\n\t"
184 "cs xchgb %b2, %c4\n\t" /* Serialize */
187 /* Read "after" TSC */
189 /* Retrieve "before" TSC on stack */
191 /* Disable interrupts */
194 : "=a" ( after ), "=d" ( before ), "=q" ( temp )
195 : "2" ( 0 ), "p" ( __from_text16 ( &rtc_flag ) ) );
197 return ( after - before );
200 PROVIDE_ENTROPY_INLINE ( rtc, min_entropy_per_sample );
201 PROVIDE_ENTROPY ( rtc, entropy_enable, rtc_entropy_enable );
202 PROVIDE_ENTROPY ( rtc, entropy_disable, rtc_entropy_disable );
203 PROVIDE_ENTROPY_INLINE ( rtc, get_noise );