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