]>
Commit | Line | Data |
---|---|---|
79e4f2a5 RN |
1 | /*++ @file\r |
2 | POSIX Pthreads to emulate APs and implement threads\r | |
3 | \r | |
4 | Copyright (c) 2011, Apple Inc. All rights reserved.\r | |
538d8aaa | 5 | Copyright (c) 2011 - 2019, Intel Corporation. All rights reserved.<BR>\r |
79e4f2a5 | 6 | \r |
e3ba31da | 7 | SPDX-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 |
15 | UINTN\r |
16 | EFIAPI\r | |
17 | PthreadMutexLock (\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 |
24 | UINTN\r |
25 | EFIAPI\r | |
26 | PthreadMutexUnLock (\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 |
33 | UINTN\r |
34 | EFIAPI\r | |
35 | PthreadMutexTryLock (\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 |
42 | VOID *\r |
43 | PthreadMutexInit (\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 |
59 | UINTN\r |
60 | PthreadMutexDestroy (\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 | |
72 | typedef 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 | 77 | THREAD_MANGLE mThreadMangle = {\r |
79e4f2a5 RN |
78 | PTHREAD_MUTEX_INITIALIZER,\r |
79 | NULL\r | |
80 | };\r | |
81 | \r | |
82 | VOID *\r | |
83 | SecFakePthreadStart (\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 | |
109 | UINTN\r | |
110 | PthreadCreate (\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 |
148 | VOID\r |
149 | PthreadExit (\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 |
157 | UINTN\r |
158 | PthreadSelf (\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 | 168 | EMU_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 |
179 | EFI_STATUS\r |
180 | PthreadOpen (\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 |
199 | EFI_STATUS\r |
200 | PthreadClose (\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 | 207 | EMU_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 |