[efi] Generalise EFI entropy generation to non-x86 CPUs
[ipxe.git] / src / interface / efi / efi_timer.c
1 /*
2 * Copyright (C) 2008 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
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #include <string.h>
27 #include <errno.h>
28 #include <unistd.h>
29 #include <ipxe/timer.h>
30 #include <ipxe/init.h>
31 #include <ipxe/efi/efi.h>
32
33 /** @file
34 *
35 * iPXE timer API for EFI
36 *
37 */
38
39 /** Current tick count */
40 static unsigned long efi_jiffies;
41
42 /** Timer tick event */
43 static EFI_EVENT efi_tick_event;
44
45 /** Colour for debug messages */
46 #define colour &efi_jiffies
47
48 /**
49 * Delay for a fixed number of microseconds
50 *
51 * @v usecs Number of microseconds for which to delay
52 */
53 static void efi_udelay ( unsigned long usecs ) {
54 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
55 EFI_STATUS efirc;
56 int rc;
57
58 if ( ( efirc = bs->Stall ( usecs ) ) != 0 ) {
59 rc = -EEFI ( efirc );
60 DBGC ( colour, "EFI could not delay for %ldus: %s\n",
61 usecs, strerror ( rc ) );
62 /* Probably screwed */
63 }
64 }
65
66 /**
67 * Get current system time in ticks
68 *
69 * @ret ticks Current time, in ticks
70 */
71 static unsigned long efi_currticks ( void ) {
72
73 return efi_jiffies;
74 }
75
76 /**
77 * Timer tick
78 *
79 * @v event Timer tick event
80 * @v context Event context
81 */
82 static EFIAPI void efi_tick ( EFI_EVENT event __unused,
83 void *context __unused ) {
84
85 /* Increment tick count */
86 efi_jiffies++;
87 }
88
89 /**
90 * Start timer tick
91 *
92 */
93 static void efi_tick_startup ( void ) {
94 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
95 EFI_STATUS efirc;
96 int rc;
97
98 /* Create timer tick event */
99 if ( ( efirc = bs->CreateEvent ( ( EVT_TIMER | EVT_NOTIFY_SIGNAL ),
100 TPL_CALLBACK, efi_tick, NULL,
101 &efi_tick_event ) ) != 0 ) {
102 rc = -EEFI ( efirc );
103 DBGC ( colour, "EFI could not create timer tick: %s\n",
104 strerror ( rc ) );
105 /* Nothing we can do about it */
106 return;
107 }
108
109 /* Start timer tick */
110 if ( ( efirc = bs->SetTimer ( efi_tick_event, TimerPeriodic,
111 ( 10000000 / EFI_TICKS_PER_SEC ) ) ) !=0){
112 rc = -EEFI ( efirc );
113 DBGC ( colour, "EFI could not start timer tick: %s\n",
114 strerror ( rc ) );
115 /* Nothing we can do about it */
116 return;
117 }
118 DBGC ( colour, "EFI timer started at %d ticks per second\n",
119 EFI_TICKS_PER_SEC );
120 }
121
122 /**
123 * Stop timer tick
124 *
125 * @v booting System is shutting down in order to boot
126 */
127 static void efi_tick_shutdown ( int booting __unused ) {
128 EFI_BOOT_SERVICES *bs = efi_systab->BootServices;
129
130 /* Stop timer tick */
131 bs->SetTimer ( efi_tick_event, TimerCancel, 0 );
132 DBGC ( colour, "EFI timer stopped\n" );
133
134 /* Destroy timer tick event */
135 bs->CloseEvent ( efi_tick_event );
136 }
137
138 /** Timer tick startup function */
139 struct startup_fn efi_tick_startup_fn __startup_fn ( STARTUP_EARLY ) = {
140 .startup = efi_tick_startup,
141 .shutdown = efi_tick_shutdown,
142 };
143
144 PROVIDE_TIMER ( efi, udelay, efi_udelay );
145 PROVIDE_TIMER ( efi, currticks, efi_currticks );
146 PROVIDE_TIMER_INLINE ( efi, ticks_per_sec );