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