]> git.proxmox.com Git - mirror_edk2.git/blob - InOsEmuPkg/Unix/Sec/EmuThunk.c
abae70b89abcc805fca513a6622d49ef06fcb07f
[mirror_edk2.git] / InOsEmuPkg / Unix / Sec / EmuThunk.c
1 /*++ @file
2 Since the SEC is the only program in our emulation we
3 must use a UEFI/PI mechanism to export APIs to other modules.
4 This is the role of the EFI_EMU_THUNK_PROTOCOL.
5
6 The mUnixThunkTable exists so that a change to EFI_EMU_THUNK_PROTOCOL
7 will cause an error in initializing the array if all the member functions
8 are not added. It looks like adding a element to end and not initializing
9 it may cause the table to be initaliized with the members at the end being
10 set to zero. This is bad as jumping to zero will crash.
11
12 Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
13 Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
14 This program and the accompanying materials
15 are licensed and made available under the terms and conditions of the BSD License
16 which accompanies this distribution. The full text of the license may be found at
17 http://opensource.org/licenses/bsd-license.php
18
19 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
20 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21
22 **/
23
24 #include "SecMain.h"
25
26 #ifdef __APPLE__
27 #define DebugAssert _Mangle__DebugAssert
28
29 #include <assert.h>
30 #include <CoreServices/CoreServices.h>
31 #include <mach/mach.h>
32 #include <mach/mach_time.h>
33
34 #undef DebugAssert
35 #endif
36
37 int settimer_initialized;
38 struct timeval settimer_timeval;
39 void (*settimer_callback)(UINT64 delta);
40
41 BOOLEAN gEmulatorInterruptEnabled = FALSE;
42
43
44 UINTN
45 SecWriteStdErr (
46 IN UINT8 *Buffer,
47 IN UINTN NumberOfBytes
48 )
49 {
50 ssize_t Return;
51
52 Return = write (1, (const void *)Buffer, (size_t)NumberOfBytes);
53
54 return (Return == -1) ? 0 : Return;
55 }
56
57
58
59 void
60 settimer_handler (int sig)
61 {
62 struct timeval timeval;
63 UINT64 delta;
64
65 gettimeofday (&timeval, NULL);
66 delta = ((UINT64)timeval.tv_sec * 1000) + (timeval.tv_usec / 1000)
67 - ((UINT64)settimer_timeval.tv_sec * 1000)
68 - (settimer_timeval.tv_usec / 1000);
69 settimer_timeval = timeval;
70
71 if (settimer_callback) {
72 ReverseGasketUint64 (settimer_callback, delta);
73 }
74 }
75
76 VOID
77 SecSetTimer (
78 IN UINT64 PeriodMs,
79 IN EMU_SET_TIMER_CALLBACK CallBack
80 )
81 {
82 struct itimerval timerval;
83 UINT32 remainder;
84
85 if (!settimer_initialized) {
86 struct sigaction act;
87
88 settimer_initialized = 1;
89 act.sa_handler = settimer_handler;
90 act.sa_flags = 0;
91 sigemptyset (&act.sa_mask);
92 gEmulatorInterruptEnabled = TRUE;
93 if (sigaction (SIGALRM, &act, NULL) != 0) {
94 printf ("SetTimer: sigaction error %s\n", strerror (errno));
95 }
96 if (gettimeofday (&settimer_timeval, NULL) != 0) {
97 printf ("SetTimer: gettimeofday error %s\n", strerror (errno));
98 }
99 }
100 timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000);
101 DivU64x32Remainder(PeriodMs, 1000, &remainder);
102 timerval.it_value.tv_usec = remainder * 1000;
103 timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000);
104 timerval.it_interval = timerval.it_value;
105
106 if (setitimer (ITIMER_REAL, &timerval, NULL) != 0) {
107 printf ("SetTimer: setitimer error %s\n", strerror (errno));
108 }
109 settimer_callback = CallBack;
110 }
111
112
113 VOID
114 SecEnableInterrupt (
115 VOID
116 )
117 {
118 sigset_t sigset;
119
120 gEmulatorInterruptEnabled = TRUE;
121 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
122 // by enabling/disabling SIGALRM.
123 sigemptyset (&sigset);
124 sigaddset (&sigset, SIGALRM);
125 pthread_sigmask (SIG_UNBLOCK, &sigset, NULL);
126 }
127
128
129 VOID
130 SecDisableInterrupt (
131 VOID
132 )
133 {
134 sigset_t sigset;
135
136 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
137 // by enabling/disabling SIGALRM.
138 sigemptyset (&sigset);
139 sigaddset (&sigset, SIGALRM);
140 pthread_sigmask (SIG_BLOCK, &sigset, NULL);
141 gEmulatorInterruptEnabled = FALSE;
142 }
143
144
145 BOOLEAN
146 SecInterruptEanbled (void)
147 {
148 return gEmulatorInterruptEnabled;
149 }
150
151
152 UINT64
153 QueryPerformanceFrequency (
154 VOID
155 )
156 {
157 // Hard code to nanoseconds
158 return 1000000000ULL;
159 }
160
161 UINT64
162 QueryPerformanceCounter (
163 VOID
164 )
165 {
166 #if __APPLE__
167 UINT64 Start;
168 Nanoseconds elapsedNano;
169
170 Start = mach_absolute_time ();
171
172 // Convert to nanoseconds.
173
174 // Have to do some pointer fun because AbsoluteToNanoseconds
175 // works in terms of UnsignedWide, which is a structure rather
176 // than a proper 64-bit integer.
177 elapsedNano = AbsoluteToNanoseconds (*(AbsoluteTime *) &Start);
178
179 return *(uint64_t *) &elapsedNano;
180 #else
181 // Need to figure out what to do for Linux?
182 return 0;
183 #endif
184 }
185
186
187
188 VOID
189 SecSleep (
190 IN UINT64 Milliseconds
191 )
192 {
193 struct timespec rq, rm;
194 struct timeval start, end;
195 unsigned long MicroSec;
196
197 rq.tv_sec = Milliseconds / 1000;
198 rq.tv_nsec = (Milliseconds % 1000) * 1000000;
199
200 //
201 // nanosleep gets interrupted by our timer tic.
202 // we need to track wall clock time or we will stall for way too long
203 //
204 gettimeofday (&start, NULL);
205 end.tv_sec = start.tv_sec + rq.tv_sec;
206 MicroSec = (start.tv_usec + rq.tv_nsec/1000);
207 end.tv_usec = MicroSec % 1000000;
208 if (MicroSec > 1000000) {
209 end.tv_sec++;
210 }
211
212 while (nanosleep (&rq, &rm) == -1) {
213 if (errno != EINTR) {
214 break;
215 }
216 gettimeofday (&start, NULL);
217 if (start.tv_sec > end.tv_sec) {
218 break;
219 } if ((start.tv_sec == end.tv_sec) && (start.tv_usec > end.tv_usec)) {
220 break;
221 }
222 rq = rm;
223 }
224 }
225
226 VOID
227 SecExit (
228 UINTN Status
229 )
230 {
231 exit (Status);
232 }
233
234
235 VOID
236 SecGetTime (
237 OUT EFI_TIME *Time,
238 OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
239 )
240 {
241 struct tm *tm;
242 time_t t;
243
244 t = time (NULL);
245 tm = localtime (&t);
246
247 Time->Year = 1900 + tm->tm_year;
248 Time->Month = tm->tm_mon + 1;
249 Time->Day = tm->tm_mday;
250 Time->Hour = tm->tm_hour;
251 Time->Minute = tm->tm_min;
252 Time->Second = tm->tm_sec;
253 Time->Nanosecond = 0;
254 Time->TimeZone = timezone;
255 Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0)
256 | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0);
257
258 if (Capabilities != NULL) {
259 Capabilities->Resolution = 1;
260 Capabilities->Accuracy = 50000000;
261 Capabilities->SetsToZero = FALSE;
262 }
263 }
264
265
266
267 VOID
268 SecSetTime (
269 IN EFI_TIME *Time
270 )
271 {
272 // Don't change the time on the system
273 // We could save delta to localtime() and have SecGetTime adjust return values?
274 return;
275 }
276
277
278 EFI_STATUS
279 SecGetNextProtocol (
280 IN BOOLEAN EmuBusDriver,
281 OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL
282 )
283 {
284 return GetNextThunkProtocol (EmuBusDriver, Instance);
285 }
286
287
288 EMU_THUNK_PROTOCOL gEmuThunkProtocol = {
289 GasketSecWriteStdErr,
290 GasketSecPeCoffGetEntryPoint,
291 GasketSecPeCoffRelocateImageExtraAction,
292 GasketSecPeCoffUnloadImageExtraAction,
293 GasketSecEnableInterrupt,
294 GasketSecDisableInterrupt,
295 GasketQueryPerformanceFrequency,
296 GasketQueryPerformanceCounter,
297 GasketSecSleep,
298 GasketSecExit,
299 GasketSecGetTime,
300 GasketSecSetTime,
301 GasketSecSetTimer,
302 GasketSecGetNextProtocol
303 };
304
305
306 VOID
307 SecInitThunkProtocol (
308 VOID
309 )
310 {
311 // timezone and daylight lib globals depend on tzset be called 1st.
312 tzset ();
313 }
314