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