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