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