From af1a266670d040d2f4083ff309d732d648afba2a Mon Sep 17 00:00:00 2001 From: Angelos Mouzakitis Date: Tue, 10 Oct 2023 14:33:42 +0000 Subject: Add submodule dependency files Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec --- roms/edk2/EmulatorPkg/Unix/Host/Pthreads.c | 229 +++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 roms/edk2/EmulatorPkg/Unix/Host/Pthreads.c (limited to 'roms/edk2/EmulatorPkg/Unix/Host/Pthreads.c') diff --git a/roms/edk2/EmulatorPkg/Unix/Host/Pthreads.c b/roms/edk2/EmulatorPkg/Unix/Host/Pthreads.c new file mode 100644 index 000000000..025687c35 --- /dev/null +++ b/roms/edk2/EmulatorPkg/Unix/Host/Pthreads.c @@ -0,0 +1,229 @@ +/*++ @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.
+ +SPDX-License-Identifier: BSD-2-Clause-Patent + + +**/ + +#include "Host.h" +#include + + +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 +}; + + -- cgit 1.2.3-korg