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