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