]> git.proxmox.com Git - mirror_edk2.git/blame - InOsEmuPkg/Unix/Sec/EmuThunk.c
[InOSEmPkg] Add OS malloc and free to the Thunk.
[mirror_edk2.git] / InOsEmuPkg / Unix / Sec / EmuThunk.c
CommitLineData
949f388f 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
12Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
13Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
14This program and the accompanying materials
15are licensed and made available under the terms and conditions of the BSD License
16which accompanies this distribution. The full text of the license may be found at
17http://opensource.org/licenses/bsd-license.php
18
19THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
20WITHOUT 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
37int settimer_initialized;
38struct timeval settimer_timeval;
39void (*settimer_callback)(UINT64 delta);
40
41BOOLEAN gEmulatorInterruptEnabled = FALSE;
42
43
44UINTN
45SecWriteStdErr (
46 IN UINT8 *Buffer,
47 IN UINTN NumberOfBytes
48 )
49{
50 ssize_t Return;
51
7e284acb 52 Return = write (STDERR_FILENO, (const void *)Buffer, (size_t)NumberOfBytes);
949f388f 53
54 return (Return == -1) ? 0 : Return;
55}
56
57
7e284acb 58EFI_STATUS
59SecConfigStdIn (
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
78UINTN
79SecWriteStdOut (
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
91UINTN
92SecReadStdIn (
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
104BOOLEAN
105SecPollStdIn (
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
c2175068 121VOID *
122SecMalloc (
123 IN UINTN Size
124 )
125{
126 return malloc ((size_t)Size);
127}
128
129VOID
130SecFree (
131 IN VOID *Ptr
132 )
133{
134 free (Ptr);
135 return;
136}
137
949f388f 138
139void
140settimer_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
156VOID
157SecSetTimer (
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
193VOID
194SecEnableInterrupt (
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
209VOID
210SecDisableInterrupt (
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
225BOOLEAN
226SecInterruptEanbled (void)
227{
228 return gEmulatorInterruptEnabled;
229}
230
231
232UINT64
233QueryPerformanceFrequency (
234 VOID
235 )
236{
237 // Hard code to nanoseconds
238 return 1000000000ULL;
239}
240
241UINT64
242QueryPerformanceCounter (
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
268VOID
269SecSleep (
1ef41207 270 IN UINT64 Nanoseconds
949f388f 271 )
272{
273 struct timespec rq, rm;
274 struct timeval start, end;
275 unsigned long MicroSec;
276
54e0b04c 277 rq.tv_sec = DivU64x32 (Nanoseconds, 1000000000);
278 rq.tv_nsec = ModU64x32 (Nanoseconds, 1000000000);
949f388f 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
57c7d70f 306
307VOID
308SecCpuSleep (
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
949f388f 322VOID
323SecExit (
324 UINTN Status
325 )
326{
327 exit (Status);
328}
329
330
331VOID
332SecGetTime (
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
363VOID
364SecSetTime (
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
374EFI_STATUS
375SecGetNextProtocol (
376 IN BOOLEAN EmuBusDriver,
377 OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL
378 )
379{
380 return GetNextThunkProtocol (EmuBusDriver, Instance);
381}
382
383
384EMU_THUNK_PROTOCOL gEmuThunkProtocol = {
385 GasketSecWriteStdErr,
7e284acb 386 GasketSecConfigStdIn,
387 GasketSecWriteStdOut,
388 GasketSecReadStdIn,
389 GasketSecPollStdIn,
c2175068 390 GasketSecMalloc,
391 GasketSecFree,
949f388f 392 GasketSecPeCoffGetEntryPoint,
393 GasketSecPeCoffRelocateImageExtraAction,
394 GasketSecPeCoffUnloadImageExtraAction,
395 GasketSecEnableInterrupt,
396 GasketSecDisableInterrupt,
397 GasketQueryPerformanceFrequency,
398 GasketQueryPerformanceCounter,
399 GasketSecSleep,
57c7d70f 400 GasketSecCpuSleep,
949f388f 401 GasketSecExit,
402 GasketSecGetTime,
403 GasketSecSetTime,
404 GasketSecSetTimer,
405 GasketSecGetNextProtocol
406};
407
408
409VOID
410SecInitThunkProtocol (
411 VOID
412 )
413{
414 // timezone and daylight lib globals depend on tzset be called 1st.
415 tzset ();
416}
417