]> git.proxmox.com Git - mirror_edk2.git/blob - InOsEmuPkg/Unix/Sec/EmuThunk.c
[InOSEmPkg] Add OS malloc and free to the Thunk.
[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 VOID *
122 SecMalloc (
123 IN UINTN Size
124 )
125 {
126 return malloc ((size_t)Size);
127 }
128
129 VOID
130 SecFree (
131 IN VOID *Ptr
132 )
133 {
134 free (Ptr);
135 return;
136 }
137
138
139 void
140 settimer_handler (int sig)
141 {
142 struct timeval timeval;
143 UINT64 delta;
144
145 gettimeofday (&timeval, NULL);
146 delta = ((UINT64)timeval.tv_sec * 1000) + (timeval.tv_usec / 1000)
147 - ((UINT64)settimer_timeval.tv_sec * 1000)
148 - (settimer_timeval.tv_usec / 1000);
149 settimer_timeval = timeval;
150
151 if (settimer_callback) {
152 ReverseGasketUint64 (settimer_callback, delta);
153 }
154 }
155
156 VOID
157 SecSetTimer (
158 IN UINT64 PeriodMs,
159 IN EMU_SET_TIMER_CALLBACK CallBack
160 )
161 {
162 struct itimerval timerval;
163 UINT32 remainder;
164
165 if (!settimer_initialized) {
166 struct sigaction act;
167
168 settimer_initialized = 1;
169 act.sa_handler = settimer_handler;
170 act.sa_flags = 0;
171 sigemptyset (&act.sa_mask);
172 gEmulatorInterruptEnabled = TRUE;
173 if (sigaction (SIGALRM, &act, NULL) != 0) {
174 printf ("SetTimer: sigaction error %s\n", strerror (errno));
175 }
176 if (gettimeofday (&settimer_timeval, NULL) != 0) {
177 printf ("SetTimer: gettimeofday error %s\n", strerror (errno));
178 }
179 }
180 timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000);
181 DivU64x32Remainder(PeriodMs, 1000, &remainder);
182 timerval.it_value.tv_usec = remainder * 1000;
183 timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000);
184 timerval.it_interval = timerval.it_value;
185
186 if (setitimer (ITIMER_REAL, &timerval, NULL) != 0) {
187 printf ("SetTimer: setitimer error %s\n", strerror (errno));
188 }
189 settimer_callback = CallBack;
190 }
191
192
193 VOID
194 SecEnableInterrupt (
195 VOID
196 )
197 {
198 sigset_t sigset;
199
200 gEmulatorInterruptEnabled = TRUE;
201 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
202 // by enabling/disabling SIGALRM.
203 sigemptyset (&sigset);
204 sigaddset (&sigset, SIGALRM);
205 pthread_sigmask (SIG_UNBLOCK, &sigset, NULL);
206 }
207
208
209 VOID
210 SecDisableInterrupt (
211 VOID
212 )
213 {
214 sigset_t sigset;
215
216 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
217 // by enabling/disabling SIGALRM.
218 sigemptyset (&sigset);
219 sigaddset (&sigset, SIGALRM);
220 pthread_sigmask (SIG_BLOCK, &sigset, NULL);
221 gEmulatorInterruptEnabled = FALSE;
222 }
223
224
225 BOOLEAN
226 SecInterruptEanbled (void)
227 {
228 return gEmulatorInterruptEnabled;
229 }
230
231
232 UINT64
233 QueryPerformanceFrequency (
234 VOID
235 )
236 {
237 // Hard code to nanoseconds
238 return 1000000000ULL;
239 }
240
241 UINT64
242 QueryPerformanceCounter (
243 VOID
244 )
245 {
246 #if __APPLE__
247 UINT64 Start;
248 Nanoseconds elapsedNano;
249
250 Start = mach_absolute_time ();
251
252 // Convert to nanoseconds.
253
254 // Have to do some pointer fun because AbsoluteToNanoseconds
255 // works in terms of UnsignedWide, which is a structure rather
256 // than a proper 64-bit integer.
257 elapsedNano = AbsoluteToNanoseconds (*(AbsoluteTime *) &Start);
258
259 return *(uint64_t *) &elapsedNano;
260 #else
261 // Need to figure out what to do for Linux?
262 return 0;
263 #endif
264 }
265
266
267
268 VOID
269 SecSleep (
270 IN UINT64 Nanoseconds
271 )
272 {
273 struct timespec rq, rm;
274 struct timeval start, end;
275 unsigned long MicroSec;
276
277 rq.tv_sec = DivU64x32 (Nanoseconds, 1000000000);
278 rq.tv_nsec = ModU64x32 (Nanoseconds, 1000000000);
279
280 //
281 // nanosleep gets interrupted by our timer tic.
282 // we need to track wall clock time or we will stall for way too long
283 //
284 gettimeofday (&start, NULL);
285 end.tv_sec = start.tv_sec + rq.tv_sec;
286 MicroSec = (start.tv_usec + rq.tv_nsec/1000);
287 end.tv_usec = MicroSec % 1000000;
288 if (MicroSec > 1000000) {
289 end.tv_sec++;
290 }
291
292 while (nanosleep (&rq, &rm) == -1) {
293 if (errno != EINTR) {
294 break;
295 }
296 gettimeofday (&start, NULL);
297 if (start.tv_sec > end.tv_sec) {
298 break;
299 } if ((start.tv_sec == end.tv_sec) && (start.tv_usec > end.tv_usec)) {
300 break;
301 }
302 rq = rm;
303 }
304 }
305
306
307 VOID
308 SecCpuSleep (
309 VOID
310 )
311 {
312 struct timespec rq, rm;
313
314 // nanosleep gets interrupted by the timer tic
315 rq.tv_sec = 1;
316 rq.tv_nsec = 0;
317
318 nanosleep (&rq, &rm);
319 }
320
321
322 VOID
323 SecExit (
324 UINTN Status
325 )
326 {
327 exit (Status);
328 }
329
330
331 VOID
332 SecGetTime (
333 OUT EFI_TIME *Time,
334 OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
335 )
336 {
337 struct tm *tm;
338 time_t t;
339
340 t = time (NULL);
341 tm = localtime (&t);
342
343 Time->Year = 1900 + tm->tm_year;
344 Time->Month = tm->tm_mon + 1;
345 Time->Day = tm->tm_mday;
346 Time->Hour = tm->tm_hour;
347 Time->Minute = tm->tm_min;
348 Time->Second = tm->tm_sec;
349 Time->Nanosecond = 0;
350 Time->TimeZone = timezone;
351 Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0)
352 | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0);
353
354 if (Capabilities != NULL) {
355 Capabilities->Resolution = 1;
356 Capabilities->Accuracy = 50000000;
357 Capabilities->SetsToZero = FALSE;
358 }
359 }
360
361
362
363 VOID
364 SecSetTime (
365 IN EFI_TIME *Time
366 )
367 {
368 // Don't change the time on the system
369 // We could save delta to localtime() and have SecGetTime adjust return values?
370 return;
371 }
372
373
374 EFI_STATUS
375 SecGetNextProtocol (
376 IN BOOLEAN EmuBusDriver,
377 OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL
378 )
379 {
380 return GetNextThunkProtocol (EmuBusDriver, Instance);
381 }
382
383
384 EMU_THUNK_PROTOCOL gEmuThunkProtocol = {
385 GasketSecWriteStdErr,
386 GasketSecConfigStdIn,
387 GasketSecWriteStdOut,
388 GasketSecReadStdIn,
389 GasketSecPollStdIn,
390 GasketSecMalloc,
391 GasketSecFree,
392 GasketSecPeCoffGetEntryPoint,
393 GasketSecPeCoffRelocateImageExtraAction,
394 GasketSecPeCoffUnloadImageExtraAction,
395 GasketSecEnableInterrupt,
396 GasketSecDisableInterrupt,
397 GasketQueryPerformanceFrequency,
398 GasketQueryPerformanceCounter,
399 GasketSecSleep,
400 GasketSecCpuSleep,
401 GasketSecExit,
402 GasketSecGetTime,
403 GasketSecSetTime,
404 GasketSecSetTimer,
405 GasketSecGetNextProtocol
406 };
407
408
409 VOID
410 SecInitThunkProtocol (
411 VOID
412 )
413 {
414 // timezone and daylight lib globals depend on tzset be called 1st.
415 tzset ();
416 }
417