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