]>
Commit | Line | Data |
---|---|---|
949f388f | 1 | /*++ @file |
2 | Since the SEC is the only program in our emulation we | |
3 | must use a UEFI/PI mechanism to export APIs to other modules. | |
4 | This is the role of the EFI_EMU_THUNK_PROTOCOL. | |
5 | ||
6 | The mUnixThunkTable exists so that a change to EFI_EMU_THUNK_PROTOCOL | |
7 | will cause an error in initializing the array if all the member functions | |
8 | are not added. It looks like adding a element to end and not initializing | |
9 | it may cause the table to be initaliized with the members at the end being | |
10 | set to zero. This is bad as jumping to zero will crash. | |
11 | ||
12 | Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR> | |
13 | Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR> | |
14 | This program and the accompanying materials | |
15 | are licensed and made available under the terms and conditions of the BSD License | |
16 | which accompanies this distribution. The full text of the license may be found at | |
17 | http://opensource.org/licenses/bsd-license.php | |
18 | ||
19 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | |
20 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | |
21 | ||
22 | **/ | |
23 | ||
24 | #include "SecMain.h" | |
25 | ||
26 | #ifdef __APPLE__ | |
27 | #define DebugAssert _Mangle__DebugAssert | |
28 | ||
29 | #include <assert.h> | |
30 | #include <CoreServices/CoreServices.h> | |
31 | #include <mach/mach.h> | |
32 | #include <mach/mach_time.h> | |
33 | ||
34 | #undef DebugAssert | |
35 | #endif | |
36 | ||
37 | int settimer_initialized; | |
38 | struct timeval settimer_timeval; | |
39 | void (*settimer_callback)(UINT64 delta); | |
40 | ||
41 | BOOLEAN gEmulatorInterruptEnabled = FALSE; | |
42 | ||
43 | ||
44 | UINTN | |
45 | SecWriteStdErr ( | |
46 | IN UINT8 *Buffer, | |
47 | IN UINTN NumberOfBytes | |
48 | ) | |
49 | { | |
50 | ssize_t Return; | |
51 | ||
52 | Return = write (1, (const void *)Buffer, (size_t)NumberOfBytes); | |
53 | ||
54 | return (Return == -1) ? 0 : Return; | |
55 | } | |
56 | ||
57 | ||
58 | ||
59 | void | |
60 | settimer_handler (int sig) | |
61 | { | |
62 | struct timeval timeval; | |
63 | UINT64 delta; | |
64 | ||
65 | gettimeofday (&timeval, NULL); | |
66 | delta = ((UINT64)timeval.tv_sec * 1000) + (timeval.tv_usec / 1000) | |
67 | - ((UINT64)settimer_timeval.tv_sec * 1000) | |
68 | - (settimer_timeval.tv_usec / 1000); | |
69 | settimer_timeval = timeval; | |
70 | ||
71 | if (settimer_callback) { | |
72 | ReverseGasketUint64 (settimer_callback, delta); | |
73 | } | |
74 | } | |
75 | ||
76 | VOID | |
77 | SecSetTimer ( | |
78 | IN UINT64 PeriodMs, | |
79 | IN EMU_SET_TIMER_CALLBACK CallBack | |
80 | ) | |
81 | { | |
82 | struct itimerval timerval; | |
83 | UINT32 remainder; | |
84 | ||
85 | if (!settimer_initialized) { | |
86 | struct sigaction act; | |
87 | ||
88 | settimer_initialized = 1; | |
89 | act.sa_handler = settimer_handler; | |
90 | act.sa_flags = 0; | |
91 | sigemptyset (&act.sa_mask); | |
92 | gEmulatorInterruptEnabled = TRUE; | |
93 | if (sigaction (SIGALRM, &act, NULL) != 0) { | |
94 | printf ("SetTimer: sigaction error %s\n", strerror (errno)); | |
95 | } | |
96 | if (gettimeofday (&settimer_timeval, NULL) != 0) { | |
97 | printf ("SetTimer: gettimeofday error %s\n", strerror (errno)); | |
98 | } | |
99 | } | |
100 | timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000); | |
101 | DivU64x32Remainder(PeriodMs, 1000, &remainder); | |
102 | timerval.it_value.tv_usec = remainder * 1000; | |
103 | timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000); | |
104 | timerval.it_interval = timerval.it_value; | |
105 | ||
106 | if (setitimer (ITIMER_REAL, &timerval, NULL) != 0) { | |
107 | printf ("SetTimer: setitimer error %s\n", strerror (errno)); | |
108 | } | |
109 | settimer_callback = CallBack; | |
110 | } | |
111 | ||
112 | ||
113 | VOID | |
114 | SecEnableInterrupt ( | |
115 | VOID | |
116 | ) | |
117 | { | |
118 | sigset_t sigset; | |
119 | ||
120 | gEmulatorInterruptEnabled = TRUE; | |
121 | // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts | |
122 | // by enabling/disabling SIGALRM. | |
123 | sigemptyset (&sigset); | |
124 | sigaddset (&sigset, SIGALRM); | |
125 | pthread_sigmask (SIG_UNBLOCK, &sigset, NULL); | |
126 | } | |
127 | ||
128 | ||
129 | VOID | |
130 | SecDisableInterrupt ( | |
131 | VOID | |
132 | ) | |
133 | { | |
134 | sigset_t sigset; | |
135 | ||
136 | // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts | |
137 | // by enabling/disabling SIGALRM. | |
138 | sigemptyset (&sigset); | |
139 | sigaddset (&sigset, SIGALRM); | |
140 | pthread_sigmask (SIG_BLOCK, &sigset, NULL); | |
141 | gEmulatorInterruptEnabled = FALSE; | |
142 | } | |
143 | ||
144 | ||
145 | BOOLEAN | |
146 | SecInterruptEanbled (void) | |
147 | { | |
148 | return gEmulatorInterruptEnabled; | |
149 | } | |
150 | ||
151 | ||
152 | UINT64 | |
153 | QueryPerformanceFrequency ( | |
154 | VOID | |
155 | ) | |
156 | { | |
157 | // Hard code to nanoseconds | |
158 | return 1000000000ULL; | |
159 | } | |
160 | ||
161 | UINT64 | |
162 | QueryPerformanceCounter ( | |
163 | VOID | |
164 | ) | |
165 | { | |
166 | #if __APPLE__ | |
167 | UINT64 Start; | |
168 | Nanoseconds elapsedNano; | |
169 | ||
170 | Start = mach_absolute_time (); | |
171 | ||
172 | // Convert to nanoseconds. | |
173 | ||
174 | // Have to do some pointer fun because AbsoluteToNanoseconds | |
175 | // works in terms of UnsignedWide, which is a structure rather | |
176 | // than a proper 64-bit integer. | |
177 | elapsedNano = AbsoluteToNanoseconds (*(AbsoluteTime *) &Start); | |
178 | ||
179 | return *(uint64_t *) &elapsedNano; | |
180 | #else | |
181 | // Need to figure out what to do for Linux? | |
182 | return 0; | |
183 | #endif | |
184 | } | |
185 | ||
186 | ||
187 | ||
188 | VOID | |
189 | SecSleep ( | |
190 | IN UINT64 Milliseconds | |
191 | ) | |
192 | { | |
193 | struct timespec rq, rm; | |
194 | struct timeval start, end; | |
195 | unsigned long MicroSec; | |
196 | ||
197 | rq.tv_sec = Milliseconds / 1000; | |
198 | rq.tv_nsec = (Milliseconds % 1000) * 1000000; | |
199 | ||
200 | // | |
201 | // nanosleep gets interrupted by our timer tic. | |
202 | // we need to track wall clock time or we will stall for way too long | |
203 | // | |
204 | gettimeofday (&start, NULL); | |
205 | end.tv_sec = start.tv_sec + rq.tv_sec; | |
206 | MicroSec = (start.tv_usec + rq.tv_nsec/1000); | |
207 | end.tv_usec = MicroSec % 1000000; | |
208 | if (MicroSec > 1000000) { | |
209 | end.tv_sec++; | |
210 | } | |
211 | ||
212 | while (nanosleep (&rq, &rm) == -1) { | |
213 | if (errno != EINTR) { | |
214 | break; | |
215 | } | |
216 | gettimeofday (&start, NULL); | |
217 | if (start.tv_sec > end.tv_sec) { | |
218 | break; | |
219 | } if ((start.tv_sec == end.tv_sec) && (start.tv_usec > end.tv_usec)) { | |
220 | break; | |
221 | } | |
222 | rq = rm; | |
223 | } | |
224 | } | |
225 | ||
226 | VOID | |
227 | SecExit ( | |
228 | UINTN Status | |
229 | ) | |
230 | { | |
231 | exit (Status); | |
232 | } | |
233 | ||
234 | ||
235 | VOID | |
236 | SecGetTime ( | |
237 | OUT EFI_TIME *Time, | |
238 | OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL | |
239 | ) | |
240 | { | |
241 | struct tm *tm; | |
242 | time_t t; | |
243 | ||
244 | t = time (NULL); | |
245 | tm = localtime (&t); | |
246 | ||
247 | Time->Year = 1900 + tm->tm_year; | |
248 | Time->Month = tm->tm_mon + 1; | |
249 | Time->Day = tm->tm_mday; | |
250 | Time->Hour = tm->tm_hour; | |
251 | Time->Minute = tm->tm_min; | |
252 | Time->Second = tm->tm_sec; | |
253 | Time->Nanosecond = 0; | |
254 | Time->TimeZone = timezone; | |
255 | Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0) | |
256 | | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0); | |
257 | ||
258 | if (Capabilities != NULL) { | |
259 | Capabilities->Resolution = 1; | |
260 | Capabilities->Accuracy = 50000000; | |
261 | Capabilities->SetsToZero = FALSE; | |
262 | } | |
263 | } | |
264 | ||
265 | ||
266 | ||
267 | VOID | |
268 | SecSetTime ( | |
269 | IN EFI_TIME *Time | |
270 | ) | |
271 | { | |
272 | // Don't change the time on the system | |
273 | // We could save delta to localtime() and have SecGetTime adjust return values? | |
274 | return; | |
275 | } | |
276 | ||
277 | ||
278 | EFI_STATUS | |
279 | SecGetNextProtocol ( | |
280 | IN BOOLEAN EmuBusDriver, | |
281 | OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL | |
282 | ) | |
283 | { | |
284 | return GetNextThunkProtocol (EmuBusDriver, Instance); | |
285 | } | |
286 | ||
287 | ||
288 | EMU_THUNK_PROTOCOL gEmuThunkProtocol = { | |
289 | GasketSecWriteStdErr, | |
290 | GasketSecPeCoffGetEntryPoint, | |
291 | GasketSecPeCoffRelocateImageExtraAction, | |
292 | GasketSecPeCoffUnloadImageExtraAction, | |
293 | GasketSecEnableInterrupt, | |
294 | GasketSecDisableInterrupt, | |
295 | GasketQueryPerformanceFrequency, | |
296 | GasketQueryPerformanceCounter, | |
297 | GasketSecSleep, | |
298 | GasketSecExit, | |
299 | GasketSecGetTime, | |
300 | GasketSecSetTime, | |
301 | GasketSecSetTimer, | |
302 | GasketSecGetNextProtocol | |
303 | }; | |
304 | ||
305 | ||
306 | VOID | |
307 | SecInitThunkProtocol ( | |
308 | VOID | |
309 | ) | |
310 | { | |
311 | // timezone and daylight lib globals depend on tzset be called 1st. | |
312 | tzset (); | |
313 | } | |
314 |