]> git.proxmox.com Git - mirror_edk2.git/blob - InOsEmuPkg/Unix/Sec/EmuThunk.c
InOsEmuPkg: Add TimerLib for PEI, DXE_CORE, and DXE/EFI drivers/applications.
[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 (STDERR_FILENO, (const void *)Buffer, (size_t)NumberOfBytes);
53
54 return (Return == -1) ? 0 : Return;
55 }
56
57
58 EFI_STATUS
59 SecConfigStdIn (
60 VOID
61 )
62 {
63 struct termios tty;
64
65 //
66 // Need to turn off line buffering, ECHO, and make it unbuffered.
67 //
68 tcgetattr (STDIN_FILENO, &tty);
69 tty.c_lflag &= ~(ICANON | ECHO);
70 tcsetattr (STDIN_FILENO, TCSANOW, &tty);
71
72 // setvbuf (STDIN_FILENO, NULL, _IONBF, 0);
73
74 // now ioctl FIONREAD will do what we need
75 return EFI_SUCCESS;
76 }
77
78 UINTN
79 SecWriteStdOut (
80 IN UINT8 *Buffer,
81 IN UINTN NumberOfBytes
82 )
83 {
84 ssize_t Return;
85
86 Return = write (STDOUT_FILENO, (const void *)Buffer, (size_t)NumberOfBytes);
87
88 return (Return == -1) ? 0 : Return;
89 }
90
91 UINTN
92 SecReadStdIn (
93 IN UINT8 *Buffer,
94 IN UINTN NumberOfBytes
95 )
96 {
97 ssize_t Return;
98
99 Return = read (STDIN_FILENO, Buffer, (size_t)NumberOfBytes);
100
101 return (Return == -1) ? 0 : Return;
102 }
103
104 BOOLEAN
105 SecPollStdIn (
106 VOID
107 )
108 {
109 int Result;
110 int Bytes;
111
112 Result = ioctl (STDIN_FILENO, FIONREAD, &Bytes);
113 if (Result == -1) {
114 return FALSE;
115 }
116
117 return (BOOLEAN)(Bytes > 0);
118 }
119
120
121
122 void
123 settimer_handler (int sig)
124 {
125 struct timeval timeval;
126 UINT64 delta;
127
128 gettimeofday (&timeval, NULL);
129 delta = ((UINT64)timeval.tv_sec * 1000) + (timeval.tv_usec / 1000)
130 - ((UINT64)settimer_timeval.tv_sec * 1000)
131 - (settimer_timeval.tv_usec / 1000);
132 settimer_timeval = timeval;
133
134 if (settimer_callback) {
135 ReverseGasketUint64 (settimer_callback, delta);
136 }
137 }
138
139 VOID
140 SecSetTimer (
141 IN UINT64 PeriodMs,
142 IN EMU_SET_TIMER_CALLBACK CallBack
143 )
144 {
145 struct itimerval timerval;
146 UINT32 remainder;
147
148 if (!settimer_initialized) {
149 struct sigaction act;
150
151 settimer_initialized = 1;
152 act.sa_handler = settimer_handler;
153 act.sa_flags = 0;
154 sigemptyset (&act.sa_mask);
155 gEmulatorInterruptEnabled = TRUE;
156 if (sigaction (SIGALRM, &act, NULL) != 0) {
157 printf ("SetTimer: sigaction error %s\n", strerror (errno));
158 }
159 if (gettimeofday (&settimer_timeval, NULL) != 0) {
160 printf ("SetTimer: gettimeofday error %s\n", strerror (errno));
161 }
162 }
163 timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000);
164 DivU64x32Remainder(PeriodMs, 1000, &remainder);
165 timerval.it_value.tv_usec = remainder * 1000;
166 timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000);
167 timerval.it_interval = timerval.it_value;
168
169 if (setitimer (ITIMER_REAL, &timerval, NULL) != 0) {
170 printf ("SetTimer: setitimer error %s\n", strerror (errno));
171 }
172 settimer_callback = CallBack;
173 }
174
175
176 VOID
177 SecEnableInterrupt (
178 VOID
179 )
180 {
181 sigset_t sigset;
182
183 gEmulatorInterruptEnabled = TRUE;
184 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
185 // by enabling/disabling SIGALRM.
186 sigemptyset (&sigset);
187 sigaddset (&sigset, SIGALRM);
188 pthread_sigmask (SIG_UNBLOCK, &sigset, NULL);
189 }
190
191
192 VOID
193 SecDisableInterrupt (
194 VOID
195 )
196 {
197 sigset_t sigset;
198
199 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
200 // by enabling/disabling SIGALRM.
201 sigemptyset (&sigset);
202 sigaddset (&sigset, SIGALRM);
203 pthread_sigmask (SIG_BLOCK, &sigset, NULL);
204 gEmulatorInterruptEnabled = FALSE;
205 }
206
207
208 BOOLEAN
209 SecInterruptEanbled (void)
210 {
211 return gEmulatorInterruptEnabled;
212 }
213
214
215 UINT64
216 QueryPerformanceFrequency (
217 VOID
218 )
219 {
220 // Hard code to nanoseconds
221 return 1000000000ULL;
222 }
223
224 UINT64
225 QueryPerformanceCounter (
226 VOID
227 )
228 {
229 #if __APPLE__
230 UINT64 Start;
231 Nanoseconds elapsedNano;
232
233 Start = mach_absolute_time ();
234
235 // Convert to nanoseconds.
236
237 // Have to do some pointer fun because AbsoluteToNanoseconds
238 // works in terms of UnsignedWide, which is a structure rather
239 // than a proper 64-bit integer.
240 elapsedNano = AbsoluteToNanoseconds (*(AbsoluteTime *) &Start);
241
242 return *(uint64_t *) &elapsedNano;
243 #else
244 // Need to figure out what to do for Linux?
245 return 0;
246 #endif
247 }
248
249
250
251 VOID
252 SecSleep (
253 IN UINT64 Nanoseconds
254 )
255 {
256 struct timespec rq, rm;
257 struct timeval start, end;
258 unsigned long MicroSec;
259
260 rq.tv_sec = Nanoseconds / 1000000000;
261 rq.tv_nsec = Nanoseconds % 1000000000;
262
263 //
264 // nanosleep gets interrupted by our timer tic.
265 // we need to track wall clock time or we will stall for way too long
266 //
267 gettimeofday (&start, NULL);
268 end.tv_sec = start.tv_sec + rq.tv_sec;
269 MicroSec = (start.tv_usec + rq.tv_nsec/1000);
270 end.tv_usec = MicroSec % 1000000;
271 if (MicroSec > 1000000) {
272 end.tv_sec++;
273 }
274
275 while (nanosleep (&rq, &rm) == -1) {
276 if (errno != EINTR) {
277 break;
278 }
279 gettimeofday (&start, NULL);
280 if (start.tv_sec > end.tv_sec) {
281 break;
282 } if ((start.tv_sec == end.tv_sec) && (start.tv_usec > end.tv_usec)) {
283 break;
284 }
285 rq = rm;
286 }
287 }
288
289
290 VOID
291 SecCpuSleep (
292 VOID
293 )
294 {
295 struct timespec rq, rm;
296
297 // nanosleep gets interrupted by the timer tic
298 rq.tv_sec = 1;
299 rq.tv_nsec = 0;
300
301 nanosleep (&rq, &rm);
302 }
303
304
305 VOID
306 SecExit (
307 UINTN Status
308 )
309 {
310 exit (Status);
311 }
312
313
314 VOID
315 SecGetTime (
316 OUT EFI_TIME *Time,
317 OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
318 )
319 {
320 struct tm *tm;
321 time_t t;
322
323 t = time (NULL);
324 tm = localtime (&t);
325
326 Time->Year = 1900 + tm->tm_year;
327 Time->Month = tm->tm_mon + 1;
328 Time->Day = tm->tm_mday;
329 Time->Hour = tm->tm_hour;
330 Time->Minute = tm->tm_min;
331 Time->Second = tm->tm_sec;
332 Time->Nanosecond = 0;
333 Time->TimeZone = timezone;
334 Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0)
335 | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0);
336
337 if (Capabilities != NULL) {
338 Capabilities->Resolution = 1;
339 Capabilities->Accuracy = 50000000;
340 Capabilities->SetsToZero = FALSE;
341 }
342 }
343
344
345
346 VOID
347 SecSetTime (
348 IN EFI_TIME *Time
349 )
350 {
351 // Don't change the time on the system
352 // We could save delta to localtime() and have SecGetTime adjust return values?
353 return;
354 }
355
356
357 EFI_STATUS
358 SecGetNextProtocol (
359 IN BOOLEAN EmuBusDriver,
360 OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL
361 )
362 {
363 return GetNextThunkProtocol (EmuBusDriver, Instance);
364 }
365
366
367 EMU_THUNK_PROTOCOL gEmuThunkProtocol = {
368 GasketSecWriteStdErr,
369 GasketSecConfigStdIn,
370 GasketSecWriteStdOut,
371 GasketSecReadStdIn,
372 GasketSecPollStdIn,
373 GasketSecPeCoffGetEntryPoint,
374 GasketSecPeCoffRelocateImageExtraAction,
375 GasketSecPeCoffUnloadImageExtraAction,
376 GasketSecEnableInterrupt,
377 GasketSecDisableInterrupt,
378 GasketQueryPerformanceFrequency,
379 GasketQueryPerformanceCounter,
380 GasketSecSleep,
381 GasketSecCpuSleep,
382 GasketSecExit,
383 GasketSecGetTime,
384 GasketSecSetTime,
385 GasketSecSetTimer,
386 GasketSecGetNextProtocol
387 };
388
389
390 VOID
391 SecInitThunkProtocol (
392 VOID
393 )
394 {
395 // timezone and daylight lib globals depend on tzset be called 1st.
396 tzset ();
397 }
398