]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Unix/Host/EmuThunk.c
EmbeddedPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / EmulatorPkg / Unix / Host / EmuThunk.c
CommitLineData
79e4f2a5
RN
1/*++ @file\r
2 Since the SEC is the only program in our emulation we\r
3 must use a UEFI/PI mechanism to export APIs to other modules.\r
4 This is the role of the EFI_EMU_THUNK_PROTOCOL.\r
5\r
6 The mUnixThunkTable exists so that a change to EFI_EMU_THUNK_PROTOCOL\r
7 will cause an error in initializing the array if all the member functions\r
8 are not added. It looks like adding a element to end and not initializing\r
9 it may cause the table to be initaliized with the members at the end being\r
10 set to zero. This is bad as jumping to zero will crash.\r
11\r
12Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>\r
13Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>\r
14This program and the accompanying materials\r
15are licensed and made available under the terms and conditions of the BSD License\r
16which accompanies this distribution. The full text of the license may be found at\r
17http://opensource.org/licenses/bsd-license.php\r
18\r
19THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
20WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
21\r
22**/\r
23\r
24#include "Host.h"\r
25\r
26#ifdef __APPLE__\r
27#define DebugAssert _Mangle__DebugAssert\r
28\r
29#include <assert.h>\r
30#include <CoreServices/CoreServices.h>\r
31#include <mach/mach.h>\r
32#include <mach/mach_time.h>\r
33\r
34#undef DebugAssert\r
35#endif\r
36\r
37int settimer_initialized;\r
38struct timeval settimer_timeval;\r
39void (*settimer_callback)(UINT64 delta);\r
40\r
41BOOLEAN gEmulatorInterruptEnabled = FALSE;\r
42\r
43\r
44UINTN\r
45SecWriteStdErr (\r
46 IN UINT8 *Buffer,\r
47 IN UINTN NumberOfBytes\r
48 )\r
49{\r
50 ssize_t Return;\r
51\r
52 Return = write (STDERR_FILENO, (const void *)Buffer, (size_t)NumberOfBytes);\r
53\r
54 return (Return == -1) ? 0 : Return;\r
55}\r
56\r
57\r
58EFI_STATUS\r
59SecConfigStdIn (\r
60 VOID\r
61 )\r
62{\r
63 struct termios tty;\r
64\r
65 //\r
66 // Need to turn off line buffering, ECHO, and make it unbuffered.\r
67 //\r
68 tcgetattr (STDIN_FILENO, &tty);\r
69 tty.c_lflag &= ~(ICANON | ECHO);\r
70 tcsetattr (STDIN_FILENO, TCSANOW, &tty);\r
71\r
72// setvbuf (STDIN_FILENO, NULL, _IONBF, 0);\r
73\r
74 // now ioctl FIONREAD will do what we need\r
75 return EFI_SUCCESS;\r
76}\r
77\r
78UINTN\r
79SecWriteStdOut (\r
80 IN UINT8 *Buffer,\r
81 IN UINTN NumberOfBytes\r
82 )\r
83{\r
84 ssize_t Return;\r
85\r
86 Return = write (STDOUT_FILENO, (const void *)Buffer, (size_t)NumberOfBytes);\r
87\r
88 return (Return == -1) ? 0 : Return;\r
89}\r
90\r
91UINTN\r
92SecReadStdIn (\r
93 IN UINT8 *Buffer,\r
94 IN UINTN NumberOfBytes\r
95 )\r
96{\r
97 ssize_t Return;\r
98\r
99 Return = read (STDIN_FILENO, Buffer, (size_t)NumberOfBytes);\r
100\r
101 return (Return == -1) ? 0 : Return;\r
102}\r
103\r
104BOOLEAN\r
105SecPollStdIn (\r
106 VOID\r
107 )\r
108{\r
109 int Result;\r
110 int Bytes;\r
111\r
112 Result = ioctl (STDIN_FILENO, FIONREAD, &Bytes);\r
113 if (Result == -1) {\r
114 return FALSE;\r
115 }\r
116\r
117 return (BOOLEAN)(Bytes > 0);\r
118}\r
119\r
120\r
121VOID *\r
122SecMalloc (\r
123 IN UINTN Size\r
124 )\r
125{\r
126 return malloc ((size_t)Size);\r
127}\r
128\r
129VOID *\r
130SecValloc (\r
131 IN UINTN Size\r
132 )\r
133{\r
134 return valloc ((size_t)Size);\r
135}\r
136\r
137BOOLEAN\r
138SecFree (\r
139 IN VOID *Ptr\r
140 )\r
141{\r
142 if (EfiSystemMemoryRange (Ptr)) {\r
143 // If an address range is in the EFI memory map it was alloced via EFI.\r
144 // So don't free those ranges and let the caller know.\r
145 return FALSE;\r
146 }\r
147\r
148 free (Ptr);\r
149 return TRUE;\r
150}\r
151\r
152\r
153void\r
154settimer_handler (int sig)\r
155{\r
156 struct timeval timeval;\r
157 UINT64 delta;\r
158\r
159 gettimeofday (&timeval, NULL);\r
160 delta = ((UINT64)timeval.tv_sec * 1000) + (timeval.tv_usec / 1000)\r
161 - ((UINT64)settimer_timeval.tv_sec * 1000)\r
162 - (settimer_timeval.tv_usec / 1000);\r
163 settimer_timeval = timeval;\r
164\r
165 if (settimer_callback) {\r
166 ReverseGasketUint64 (settimer_callback, delta);\r
167 }\r
168}\r
169\r
170VOID\r
171SecSetTimer (\r
172 IN UINT64 PeriodMs,\r
173 IN EMU_SET_TIMER_CALLBACK CallBack\r
174 )\r
175{\r
176 struct itimerval timerval;\r
177 UINT32 remainder;\r
178\r
179 if (!settimer_initialized) {\r
180 struct sigaction act;\r
181\r
182 settimer_initialized = 1;\r
183 act.sa_handler = settimer_handler;\r
184 act.sa_flags = 0;\r
185 sigemptyset (&act.sa_mask);\r
186 gEmulatorInterruptEnabled = TRUE;\r
187 if (sigaction (SIGALRM, &act, NULL) != 0) {\r
188 printf ("SetTimer: sigaction error %s\n", strerror (errno));\r
189 }\r
190 if (gettimeofday (&settimer_timeval, NULL) != 0) {\r
191 printf ("SetTimer: gettimeofday error %s\n", strerror (errno));\r
192 }\r
193 }\r
194 timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000);\r
195 DivU64x32Remainder(PeriodMs, 1000, &remainder);\r
196 timerval.it_value.tv_usec = remainder * 1000;\r
197 timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000);\r
198 timerval.it_interval = timerval.it_value;\r
199\r
200 if (setitimer (ITIMER_REAL, &timerval, NULL) != 0) {\r
201 printf ("SetTimer: setitimer error %s\n", strerror (errno));\r
202 }\r
203 settimer_callback = CallBack;\r
204}\r
205\r
206\r
207VOID\r
208SecEnableInterrupt (\r
209 VOID\r
210 )\r
211{\r
212 sigset_t sigset;\r
213\r
214 gEmulatorInterruptEnabled = TRUE;\r
215 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts\r
216 // by enabling/disabling SIGALRM.\r
217 sigemptyset (&sigset);\r
218 sigaddset (&sigset, SIGALRM);\r
219 pthread_sigmask (SIG_UNBLOCK, &sigset, NULL);\r
220}\r
221\r
222\r
223VOID\r
224SecDisableInterrupt (\r
225 VOID\r
226 )\r
227{\r
228 sigset_t sigset;\r
229\r
230 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts\r
231 // by enabling/disabling SIGALRM.\r
232 sigemptyset (&sigset);\r
233 sigaddset (&sigset, SIGALRM);\r
234 pthread_sigmask (SIG_BLOCK, &sigset, NULL);\r
235 gEmulatorInterruptEnabled = FALSE;\r
236}\r
237\r
238\r
239BOOLEAN\r
240SecInterruptEanbled (void)\r
241{\r
242 return gEmulatorInterruptEnabled;\r
243}\r
244\r
245\r
246UINT64\r
247QueryPerformanceFrequency (\r
248 VOID\r
249 )\r
250{\r
251 // Hard code to nanoseconds\r
252 return 1000000000ULL;\r
253}\r
254\r
255UINT64\r
256QueryPerformanceCounter (\r
257 VOID\r
258 )\r
259{\r
260#if __APPLE__\r
261 UINT64 Start;\r
262 static mach_timebase_info_data_t sTimebaseInfo;\r
263\r
264\r
265 Start = mach_absolute_time ();\r
266\r
267 // Convert to nanoseconds.\r
268\r
269 // If this is the first time we've run, get the timebase.\r
270 // We can use denom == 0 to indicate that sTimebaseInfo is\r
271 // uninitialised because it makes no sense to have a zero\r
272 // denominator is a fraction.\r
273\r
274 if ( sTimebaseInfo.denom == 0 ) {\r
275 (void) mach_timebase_info(&sTimebaseInfo);\r
276 }\r
277\r
278 // Do the maths. We hope that the multiplication doesn't\r
279 // overflow; the price you pay for working in fixed point.\r
280\r
281 return (Start * sTimebaseInfo.numer) / sTimebaseInfo.denom;\r
282#else\r
283 // Need to figure out what to do for Linux?\r
284 return 0;\r
285#endif\r
286}\r
287\r
288\r
289\r
290VOID\r
291SecSleep (\r
292 IN UINT64 Nanoseconds\r
293 )\r
294{\r
295 struct timespec rq, rm;\r
296 struct timeval start, end;\r
297 unsigned long MicroSec;\r
298\r
299 rq.tv_sec = DivU64x32 (Nanoseconds, 1000000000);\r
300 rq.tv_nsec = ModU64x32 (Nanoseconds, 1000000000);\r
301\r
302 //\r
303 // nanosleep gets interrupted by our timer tic.\r
304 // we need to track wall clock time or we will stall for way too long\r
305 //\r
306 gettimeofday (&start, NULL);\r
307 end.tv_sec = start.tv_sec + rq.tv_sec;\r
308 MicroSec = (start.tv_usec + rq.tv_nsec/1000);\r
309 end.tv_usec = MicroSec % 1000000;\r
310 if (MicroSec > 1000000) {\r
311 end.tv_sec++;\r
312 }\r
313\r
314 while (nanosleep (&rq, &rm) == -1) {\r
315 if (errno != EINTR) {\r
316 break;\r
317 }\r
318 gettimeofday (&start, NULL);\r
319 if (start.tv_sec > end.tv_sec) {\r
320 break;\r
321 } if ((start.tv_sec == end.tv_sec) && (start.tv_usec > end.tv_usec)) {\r
322 break;\r
323 }\r
324 rq = rm;\r
325 }\r
326}\r
327\r
328\r
329VOID\r
330SecCpuSleep (\r
331 VOID\r
332 )\r
333{\r
334 struct timespec rq, rm;\r
335\r
336 // nanosleep gets interrupted by the timer tic\r
337 rq.tv_sec = 1;\r
338 rq.tv_nsec = 0;\r
339\r
340 nanosleep (&rq, &rm);\r
341}\r
342\r
343\r
344VOID\r
345SecExit (\r
346 UINTN Status\r
347 )\r
348{\r
349 exit (Status);\r
350}\r
351\r
352\r
353VOID\r
354SecGetTime (\r
355 OUT EFI_TIME *Time,\r
356 OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL\r
357 )\r
358{\r
359 struct tm *tm;\r
360 time_t t;\r
361\r
362 t = time (NULL);\r
363 tm = localtime (&t);\r
364\r
365 Time->Year = 1900 + tm->tm_year;\r
366 Time->Month = tm->tm_mon + 1;\r
367 Time->Day = tm->tm_mday;\r
368 Time->Hour = tm->tm_hour;\r
369 Time->Minute = tm->tm_min;\r
370 Time->Second = tm->tm_sec;\r
371 Time->Nanosecond = 0;\r
372 Time->TimeZone = timezone;\r
373 Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0)\r
374 | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0);\r
375\r
376 if (Capabilities != NULL) {\r
377 Capabilities->Resolution = 1;\r
378 Capabilities->Accuracy = 50000000;\r
379 Capabilities->SetsToZero = FALSE;\r
380 }\r
381}\r
382\r
383\r
384\r
385VOID\r
386SecSetTime (\r
387 IN EFI_TIME *Time\r
388 )\r
389{\r
390 // Don't change the time on the system\r
391 // We could save delta to localtime() and have SecGetTime adjust return values?\r
392 return;\r
393}\r
394\r
395\r
396EFI_STATUS\r
397SecGetNextProtocol (\r
398 IN BOOLEAN EmuBusDriver,\r
399 OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL\r
400 )\r
401{\r
402 return GetNextThunkProtocol (EmuBusDriver, Instance);\r
403}\r
404\r
405\r
406EMU_THUNK_PROTOCOL gEmuThunkProtocol = {\r
407 GasketSecWriteStdErr,\r
408 GasketSecConfigStdIn,\r
409 GasketSecWriteStdOut,\r
410 GasketSecReadStdIn,\r
411 GasketSecPollStdIn,\r
412 GasketSecMalloc,\r
413 GasketSecValloc,\r
414 GasketSecFree,\r
415 GasketSecPeCoffGetEntryPoint,\r
416 GasketSecPeCoffRelocateImageExtraAction,\r
417 GasketSecPeCoffUnloadImageExtraAction,\r
418 GasketSecEnableInterrupt,\r
419 GasketSecDisableInterrupt,\r
420 GasketQueryPerformanceFrequency,\r
421 GasketQueryPerformanceCounter,\r
422 GasketSecSleep,\r
423 GasketSecCpuSleep,\r
424 GasketSecExit,\r
425 GasketSecGetTime,\r
426 GasketSecSetTime,\r
427 GasketSecSetTimer,\r
428 GasketSecGetNextProtocol\r
429};\r
430\r
431\r
432VOID\r
433SecInitThunkProtocol (\r
434 VOID\r
435 )\r
436{\r
437 // timezone and daylight lib globals depend on tzset be called 1st.\r
438 tzset ();\r
439}\r
440\r