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