]>
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 | ||
7e284acb | 52 | Return = write (STDERR_FILENO, (const void *)Buffer, (size_t)NumberOfBytes); |
949f388f | 53 | |
54 | return (Return == -1) ? 0 : Return; | |
55 | } | |
56 | ||
57 | ||
7e284acb | 58 | EFI_STATUS |
59 | SecConfigStdIn ( | |
60 | VOID | |
61 | ) | |
62 | { | |
63 | struct termios tty; | |
64 | ||
65 | // | |
66 | // Need to turn off line buffering, ECHO, and make it unbuffered. | |
67 | // | |
68 | tcgetattr (STDIN_FILENO, &tty); | |
69 | tty.c_lflag &= ~(ICANON | ECHO); | |
70 | tcsetattr (STDIN_FILENO, TCSANOW, &tty); | |
71 | ||
72 | // setvbuf (STDIN_FILENO, NULL, _IONBF, 0); | |
73 | ||
74 | // now ioctl FIONREAD will do what we need | |
75 | return EFI_SUCCESS; | |
76 | } | |
77 | ||
78 | UINTN | |
79 | SecWriteStdOut ( | |
80 | IN UINT8 *Buffer, | |
81 | IN UINTN NumberOfBytes | |
82 | ) | |
83 | { | |
84 | ssize_t Return; | |
85 | ||
86 | Return = write (STDOUT_FILENO, (const void *)Buffer, (size_t)NumberOfBytes); | |
87 | ||
88 | return (Return == -1) ? 0 : Return; | |
89 | } | |
90 | ||
91 | UINTN | |
92 | SecReadStdIn ( | |
93 | IN UINT8 *Buffer, | |
94 | IN UINTN NumberOfBytes | |
95 | ) | |
96 | { | |
97 | ssize_t Return; | |
98 | ||
99 | Return = read (STDIN_FILENO, Buffer, (size_t)NumberOfBytes); | |
100 | ||
101 | return (Return == -1) ? 0 : Return; | |
102 | } | |
103 | ||
104 | BOOLEAN | |
105 | SecPollStdIn ( | |
106 | VOID | |
107 | ) | |
108 | { | |
109 | int Result; | |
110 | int Bytes; | |
111 | ||
112 | Result = ioctl (STDIN_FILENO, FIONREAD, &Bytes); | |
113 | if (Result == -1) { | |
114 | return FALSE; | |
115 | } | |
116 | ||
117 | return (BOOLEAN)(Bytes > 0); | |
118 | } | |
119 | ||
120 | ||
c2175068 | 121 | VOID * |
122 | SecMalloc ( | |
123 | IN UINTN Size | |
124 | ) | |
125 | { | |
126 | return malloc ((size_t)Size); | |
127 | } | |
128 | ||
129 | VOID | |
130 | SecFree ( | |
131 | IN VOID *Ptr | |
132 | ) | |
133 | { | |
134 | free (Ptr); | |
135 | return; | |
136 | } | |
137 | ||
949f388f | 138 | |
139 | void | |
140 | settimer_handler (int sig) | |
141 | { | |
142 | struct timeval timeval; | |
143 | UINT64 delta; | |
144 | ||
145 | gettimeofday (&timeval, NULL); | |
146 | delta = ((UINT64)timeval.tv_sec * 1000) + (timeval.tv_usec / 1000) | |
147 | - ((UINT64)settimer_timeval.tv_sec * 1000) | |
148 | - (settimer_timeval.tv_usec / 1000); | |
149 | settimer_timeval = timeval; | |
150 | ||
151 | if (settimer_callback) { | |
152 | ReverseGasketUint64 (settimer_callback, delta); | |
153 | } | |
154 | } | |
155 | ||
156 | VOID | |
157 | SecSetTimer ( | |
158 | IN UINT64 PeriodMs, | |
159 | IN EMU_SET_TIMER_CALLBACK CallBack | |
160 | ) | |
161 | { | |
162 | struct itimerval timerval; | |
163 | UINT32 remainder; | |
164 | ||
165 | if (!settimer_initialized) { | |
166 | struct sigaction act; | |
167 | ||
168 | settimer_initialized = 1; | |
169 | act.sa_handler = settimer_handler; | |
170 | act.sa_flags = 0; | |
171 | sigemptyset (&act.sa_mask); | |
172 | gEmulatorInterruptEnabled = TRUE; | |
173 | if (sigaction (SIGALRM, &act, NULL) != 0) { | |
174 | printf ("SetTimer: sigaction error %s\n", strerror (errno)); | |
175 | } | |
176 | if (gettimeofday (&settimer_timeval, NULL) != 0) { | |
177 | printf ("SetTimer: gettimeofday error %s\n", strerror (errno)); | |
178 | } | |
179 | } | |
180 | timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000); | |
181 | DivU64x32Remainder(PeriodMs, 1000, &remainder); | |
182 | timerval.it_value.tv_usec = remainder * 1000; | |
183 | timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000); | |
184 | timerval.it_interval = timerval.it_value; | |
185 | ||
186 | if (setitimer (ITIMER_REAL, &timerval, NULL) != 0) { | |
187 | printf ("SetTimer: setitimer error %s\n", strerror (errno)); | |
188 | } | |
189 | settimer_callback = CallBack; | |
190 | } | |
191 | ||
192 | ||
193 | VOID | |
194 | SecEnableInterrupt ( | |
195 | VOID | |
196 | ) | |
197 | { | |
198 | sigset_t sigset; | |
199 | ||
200 | gEmulatorInterruptEnabled = TRUE; | |
201 | // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts | |
202 | // by enabling/disabling SIGALRM. | |
203 | sigemptyset (&sigset); | |
204 | sigaddset (&sigset, SIGALRM); | |
205 | pthread_sigmask (SIG_UNBLOCK, &sigset, NULL); | |
206 | } | |
207 | ||
208 | ||
209 | VOID | |
210 | SecDisableInterrupt ( | |
211 | VOID | |
212 | ) | |
213 | { | |
214 | sigset_t sigset; | |
215 | ||
216 | // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts | |
217 | // by enabling/disabling SIGALRM. | |
218 | sigemptyset (&sigset); | |
219 | sigaddset (&sigset, SIGALRM); | |
220 | pthread_sigmask (SIG_BLOCK, &sigset, NULL); | |
221 | gEmulatorInterruptEnabled = FALSE; | |
222 | } | |
223 | ||
224 | ||
225 | BOOLEAN | |
226 | SecInterruptEanbled (void) | |
227 | { | |
228 | return gEmulatorInterruptEnabled; | |
229 | } | |
230 | ||
231 | ||
232 | UINT64 | |
233 | QueryPerformanceFrequency ( | |
234 | VOID | |
235 | ) | |
236 | { | |
237 | // Hard code to nanoseconds | |
238 | return 1000000000ULL; | |
239 | } | |
240 | ||
241 | UINT64 | |
242 | QueryPerformanceCounter ( | |
243 | VOID | |
244 | ) | |
245 | { | |
246 | #if __APPLE__ | |
247 | UINT64 Start; | |
248 | Nanoseconds elapsedNano; | |
249 | ||
250 | Start = mach_absolute_time (); | |
251 | ||
252 | // Convert to nanoseconds. | |
253 | ||
254 | // Have to do some pointer fun because AbsoluteToNanoseconds | |
255 | // works in terms of UnsignedWide, which is a structure rather | |
256 | // than a proper 64-bit integer. | |
257 | elapsedNano = AbsoluteToNanoseconds (*(AbsoluteTime *) &Start); | |
258 | ||
259 | return *(uint64_t *) &elapsedNano; | |
260 | #else | |
261 | // Need to figure out what to do for Linux? | |
262 | return 0; | |
263 | #endif | |
264 | } | |
265 | ||
266 | ||
267 | ||
268 | VOID | |
269 | SecSleep ( | |
1ef41207 | 270 | IN UINT64 Nanoseconds |
949f388f | 271 | ) |
272 | { | |
273 | struct timespec rq, rm; | |
274 | struct timeval start, end; | |
275 | unsigned long MicroSec; | |
276 | ||
54e0b04c | 277 | rq.tv_sec = DivU64x32 (Nanoseconds, 1000000000); |
278 | rq.tv_nsec = ModU64x32 (Nanoseconds, 1000000000); | |
949f388f | 279 | |
280 | // | |
281 | // nanosleep gets interrupted by our timer tic. | |
282 | // we need to track wall clock time or we will stall for way too long | |
283 | // | |
284 | gettimeofday (&start, NULL); | |
285 | end.tv_sec = start.tv_sec + rq.tv_sec; | |
286 | MicroSec = (start.tv_usec + rq.tv_nsec/1000); | |
287 | end.tv_usec = MicroSec % 1000000; | |
288 | if (MicroSec > 1000000) { | |
289 | end.tv_sec++; | |
290 | } | |
291 | ||
292 | while (nanosleep (&rq, &rm) == -1) { | |
293 | if (errno != EINTR) { | |
294 | break; | |
295 | } | |
296 | gettimeofday (&start, NULL); | |
297 | if (start.tv_sec > end.tv_sec) { | |
298 | break; | |
299 | } if ((start.tv_sec == end.tv_sec) && (start.tv_usec > end.tv_usec)) { | |
300 | break; | |
301 | } | |
302 | rq = rm; | |
303 | } | |
304 | } | |
305 | ||
57c7d70f | 306 | |
307 | VOID | |
308 | SecCpuSleep ( | |
309 | VOID | |
310 | ) | |
311 | { | |
312 | struct timespec rq, rm; | |
313 | ||
314 | // nanosleep gets interrupted by the timer tic | |
315 | rq.tv_sec = 1; | |
316 | rq.tv_nsec = 0; | |
317 | ||
318 | nanosleep (&rq, &rm); | |
319 | } | |
320 | ||
321 | ||
949f388f | 322 | VOID |
323 | SecExit ( | |
324 | UINTN Status | |
325 | ) | |
326 | { | |
327 | exit (Status); | |
328 | } | |
329 | ||
330 | ||
331 | VOID | |
332 | SecGetTime ( | |
333 | OUT EFI_TIME *Time, | |
334 | OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL | |
335 | ) | |
336 | { | |
337 | struct tm *tm; | |
338 | time_t t; | |
339 | ||
340 | t = time (NULL); | |
341 | tm = localtime (&t); | |
342 | ||
343 | Time->Year = 1900 + tm->tm_year; | |
344 | Time->Month = tm->tm_mon + 1; | |
345 | Time->Day = tm->tm_mday; | |
346 | Time->Hour = tm->tm_hour; | |
347 | Time->Minute = tm->tm_min; | |
348 | Time->Second = tm->tm_sec; | |
349 | Time->Nanosecond = 0; | |
350 | Time->TimeZone = timezone; | |
351 | Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0) | |
352 | | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0); | |
353 | ||
354 | if (Capabilities != NULL) { | |
355 | Capabilities->Resolution = 1; | |
356 | Capabilities->Accuracy = 50000000; | |
357 | Capabilities->SetsToZero = FALSE; | |
358 | } | |
359 | } | |
360 | ||
361 | ||
362 | ||
363 | VOID | |
364 | SecSetTime ( | |
365 | IN EFI_TIME *Time | |
366 | ) | |
367 | { | |
368 | // Don't change the time on the system | |
369 | // We could save delta to localtime() and have SecGetTime adjust return values? | |
370 | return; | |
371 | } | |
372 | ||
373 | ||
374 | EFI_STATUS | |
375 | SecGetNextProtocol ( | |
376 | IN BOOLEAN EmuBusDriver, | |
377 | OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL | |
378 | ) | |
379 | { | |
380 | return GetNextThunkProtocol (EmuBusDriver, Instance); | |
381 | } | |
382 | ||
383 | ||
384 | EMU_THUNK_PROTOCOL gEmuThunkProtocol = { | |
385 | GasketSecWriteStdErr, | |
7e284acb | 386 | GasketSecConfigStdIn, |
387 | GasketSecWriteStdOut, | |
388 | GasketSecReadStdIn, | |
389 | GasketSecPollStdIn, | |
c2175068 | 390 | GasketSecMalloc, |
391 | GasketSecFree, | |
949f388f | 392 | GasketSecPeCoffGetEntryPoint, |
393 | GasketSecPeCoffRelocateImageExtraAction, | |
394 | GasketSecPeCoffUnloadImageExtraAction, | |
395 | GasketSecEnableInterrupt, | |
396 | GasketSecDisableInterrupt, | |
397 | GasketQueryPerformanceFrequency, | |
398 | GasketQueryPerformanceCounter, | |
399 | GasketSecSleep, | |
57c7d70f | 400 | GasketSecCpuSleep, |
949f388f | 401 | GasketSecExit, |
402 | GasketSecGetTime, | |
403 | GasketSecSetTime, | |
404 | GasketSecSetTimer, | |
405 | GasketSecGetNextProtocol | |
406 | }; | |
407 | ||
408 | ||
409 | VOID | |
410 | SecInitThunkProtocol ( | |
411 | VOID | |
412 | ) | |
413 | { | |
414 | // timezone and daylight lib globals depend on tzset be called 1st. | |
415 | tzset (); | |
416 | } | |
417 |