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