Home | History | Annotate | Download | only in Host
      1 /*++ @file
      2  POSIX Pthreads to emulate APs and implement threads
      3 
      4 Copyright (c) 2011, Apple Inc. All rights reserved.
      5 Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
      6 
      7 This program and the accompanying materials
      8 are licensed and made available under the terms and conditions of the BSD License
      9 which accompanies this distribution.  The full text of the license may be found at
     10 http://opensource.org/licenses/bsd-license.php
     11 
     12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     14 
     15 
     16 **/
     17 
     18 #include "Host.h"
     19 #include <pthread.h>
     20 
     21 
     22 UINTN
     23 EFIAPI
     24 PthreadMutexLock (
     25   IN VOID *Mutex
     26   )
     27 {
     28   return (UINTN)pthread_mutex_lock ((pthread_mutex_t *)Mutex);
     29 }
     30 
     31 
     32 
     33 UINTN
     34 EFIAPI
     35 PthreadMutexUnLock (
     36   IN VOID *Mutex
     37   )
     38 {
     39   return (UINTN)pthread_mutex_unlock ((pthread_mutex_t *)Mutex);
     40 }
     41 
     42 
     43 UINTN
     44 EFIAPI
     45 PthreadMutexTryLock (
     46   IN VOID *Mutex
     47   )
     48 {
     49   return (UINTN)pthread_mutex_trylock ((pthread_mutex_t *)Mutex);
     50 }
     51 
     52 
     53 VOID *
     54 PthreadMutexInit (
     55   IN VOID
     56   )
     57 {
     58   pthread_mutex_t *Mutex;
     59   int             err;
     60 
     61   Mutex = malloc (sizeof (pthread_mutex_t));
     62   err = pthread_mutex_init (Mutex, NULL);
     63   if (err == 0) {
     64     return Mutex;
     65   }
     66 
     67   return NULL;
     68 }
     69 
     70 
     71 UINTN
     72 PthreadMutexDestroy (
     73   IN VOID *Mutex
     74   )
     75 {
     76   if (Mutex != NULL) {
     77     return pthread_mutex_destroy ((pthread_mutex_t *)Mutex);
     78   }
     79 
     80   return -1;
     81 }
     82 
     83 // Can't store this data on PthreadCreate stack so we need a global
     84 typedef struct {
     85   pthread_mutex_t             Mutex;
     86   THREAD_THUNK_THREAD_ENTRY   Start;
     87 } THREAD_MANGLE;
     88 
     89 THREAD_MANGLE mThreadMangle = {
     90   PTHREAD_MUTEX_INITIALIZER,
     91   NULL
     92 };
     93 
     94 VOID *
     95 SecFakePthreadStart (
     96   VOID  *Context
     97   )
     98 {
     99   THREAD_THUNK_THREAD_ENTRY Start;
    100   sigset_t                  SigMask;
    101 
    102   // Save global on the stack before we unlock
    103   Start   = mThreadMangle.Start;
    104   pthread_mutex_unlock (&mThreadMangle.Mutex);
    105 
    106   // Mask all signals to the APs
    107   sigfillset (&SigMask);
    108   pthread_sigmask (SIG_BLOCK, &SigMask, NULL);
    109 
    110   //
    111   // We have to start the thread in SEC as we need to follow
    112   // OS X calling conventions. We can then call back into
    113   // to the callers Start.
    114   //
    115   // This is a great example of how all problems in computer
    116   // science can be solved by adding another level of indirection
    117   //
    118  return  (VOID *)ReverseGasketUint64 ((CALL_BACK)Start, (UINTN)Context);
    119 }
    120 
    121 UINTN
    122 PthreadCreate (
    123   IN  VOID                      *Thread,
    124   IN  VOID                      *Attribute,
    125   IN  THREAD_THUNK_THREAD_ENTRY Start,
    126   IN  VOID                      *Context
    127   )
    128 {
    129   int         err;
    130   BOOLEAN     EnabledOnEntry;
    131 
    132   //
    133   // Threads inherit interrupt state so disable interrupts before we start thread
    134   //
    135   if (SecInterruptEanbled ()) {
    136     SecDisableInterrupt ();
    137     EnabledOnEntry = TRUE;
    138   } else {
    139     EnabledOnEntry = FALSE;
    140   }
    141 
    142   // Aquire lock for global, SecFakePthreadStart runs in a different thread.
    143   pthread_mutex_lock (&mThreadMangle.Mutex);
    144   mThreadMangle.Start   = Start;
    145 
    146   err = pthread_create (Thread, Attribute, SecFakePthreadStart, Context);
    147   if (err != 0) {
    148     // Thread failed to launch so release the lock;
    149     pthread_mutex_unlock (&mThreadMangle.Mutex);
    150   }
    151 
    152   if (EnabledOnEntry) {
    153     // Restore interrupt state
    154     SecEnableInterrupt ();
    155   }
    156 
    157   return err;
    158 }
    159 
    160 
    161 VOID
    162 PthreadExit (
    163   IN VOID *ValuePtr
    164   )
    165 {
    166   pthread_exit (ValuePtr);
    167   return;
    168 }
    169 
    170 
    171 UINTN
    172 PthreadSelf (
    173   VOID
    174   )
    175 {
    176   // POSIX currently allows pthread_t to be a structure or arithmetic type.
    177   // Check out sys/types.h to make sure this will work if you are porting.
    178   // On OS X (Darwin) pthread_t is a pointer to a structure so this code works.
    179   return (UINTN)pthread_self ();
    180 }
    181 
    182 
    183 EMU_THREAD_THUNK_PROTOCOL gPthreadThunk = {
    184   GasketPthreadMutexLock,
    185   GasketPthreadMutexUnLock,
    186   GasketPthreadMutexTryLock,
    187   GasketPthreadMutexInit,
    188   GasketPthreadMutexDestroy,
    189   GasketPthreadCreate,
    190   GasketPthreadExit,
    191   GasketPthreadSelf
    192 };
    193 
    194 
    195 EFI_STATUS
    196 PthreadOpen (
    197   IN  EMU_IO_THUNK_PROTOCOL   *This
    198   )
    199 {
    200   if (This->Instance != 0) {
    201     // Only single instance is supported
    202     return EFI_NOT_FOUND;
    203   }
    204 
    205   if (This->ConfigString[0] == L'0') {
    206     // If AP count is zero no need for threads
    207     return EFI_NOT_FOUND;
    208   }
    209 
    210   This->Interface = &gPthreadThunk;
    211 
    212   return EFI_SUCCESS;
    213 }
    214 
    215 
    216 EFI_STATUS
    217 PthreadClose (
    218   IN  EMU_IO_THUNK_PROTOCOL   *This
    219   )
    220 {
    221   return EFI_SUCCESS;
    222 }
    223 
    224 
    225 EMU_IO_THUNK_PROTOCOL gPthreadThunkIo = {
    226   &gEmuThreadThunkProtocolGuid,
    227   NULL,
    228   NULL,
    229   0,
    230   GasketPthreadOpen,
    231   GasketPthreadClose,
    232   NULL
    233 };
    234 
    235 
    236