]> git.proxmox.com Git - mirror_edk2.git/blame - 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
CommitLineData
949f388f 1/*++ @file
2 POSIX Pthreads to emulate APs and implement threads
3
4Copyright (c) 2011, Apple Inc. All rights reserved.
5This program and the accompanying materials
6are licensed and made available under the terms and conditions of the BSD License
7which accompanies this distribution. The full text of the license may be found at
8http://opensource.org/licenses/bsd-license.php
9
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13
14**/
15
16#include "SecMain.h"
17#include <pthread.h>
18
19
20UINTN
21EFIAPI
22PthreadMutexLock (
23 IN VOID *Mutex
24 )
25{
26 return (UINTN)pthread_mutex_lock ((pthread_mutex_t *)Mutex);
27}
28
29
30
31UINTN
32EFIAPI
33PthreadMutexUnLock (
34 IN VOID *Mutex
35 )
36{
37 return (UINTN)pthread_mutex_unlock ((pthread_mutex_t *)Mutex);
38}
39
40
41UINTN
42EFIAPI
43PthreadMutexTryLock (
44 IN VOID *Mutex
45 )
46{
47 return (UINTN)pthread_mutex_trylock ((pthread_mutex_t *)Mutex);
48}
49
50
51VOID *
52PthreadMutexInit (
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
69UINTN
70PthreadMutexDestroy (
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
82typedef struct {
83 pthread_mutex_t Mutex;
84 PTREAD_THUNK_THEAD_ENTRY Start;
85} THREAD_MANGLE;
86
87THREAD_MANGLE mThreadMangle = {
88 PTHREAD_MUTEX_INITIALIZER,
89 NULL
90};
91
92VOID *
93SecFakePthreadStart (
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
119UINTN
120PthreadCreate (
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
159VOID
160PthreadExit (
161 IN VOID *ValuePtr
162 )
163{
164 pthread_exit (ValuePtr);
165 return;
166}
167
168
169UINTN
170PthreadSelf (
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
181EMU_PTREAD_THUNK_PROTOCOL gPthreadThunk = {
182 GasketPthreadMutexLock,
183 GasketPthreadMutexUnLock,
184 GasketPthreadMutexTryLock,
185 GasketPthreadMutexInit,
186 GasketPthreadMutexDestroy,
187 GasketPthreadCreate,
188 GasketPthreadExit,
189 GasketPthreadSelf
190};
191
192
193EFI_STATUS
194PthreadOpen (
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
214EFI_STATUS
215PthreadClose (
216 IN EMU_IO_THUNK_PROTOCOL *This
217 )
218{
219 return EFI_SUCCESS;
220}
221
222
223EMU_IO_THUNK_PROTOCOL gPthreadThunkIo = {
224 &gEmuPthreadThunkProtocolGuid,
225 NULL,
226 NULL,
227 0,
228 GasketPthreadOpen,
229 GasketPthreadClose,
230 NULL
231};
232
233