]> git.proxmox.com Git - mirror_edk2.git/blame - InOsEmuPkg/Unix/Sec/EmuThunk.c
InOsEmuPkg/Unix: Detect lib directory suffix on Linux
[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
949f388f 121
122void
123settimer_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
139VOID
140SecSetTimer (
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
176VOID
177SecEnableInterrupt (
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
192VOID
193SecDisableInterrupt (
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
208BOOLEAN
209SecInterruptEanbled (void)
210{
211 return gEmulatorInterruptEnabled;
212}
213
214
215UINT64
216QueryPerformanceFrequency (
217 VOID
218 )
219{
220 // Hard code to nanoseconds
221 return 1000000000ULL;
222}
223
224UINT64
225QueryPerformanceCounter (
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
251VOID
252SecSleep (
1ef41207 253 IN UINT64 Nanoseconds
949f388f 254 )
255{
256 struct timespec rq, rm;
257 struct timeval start, end;
258 unsigned long MicroSec;
259
1ef41207 260 rq.tv_sec = Nanoseconds / 1000000000;
261 rq.tv_nsec = Nanoseconds % 1000000000;
949f388f 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
57c7d70f 289
290VOID
291SecCpuSleep (
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
949f388f 305VOID
306SecExit (
307 UINTN Status
308 )
309{
310 exit (Status);
311}
312
313
314VOID
315SecGetTime (
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
346VOID
347SecSetTime (
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
357EFI_STATUS
358SecGetNextProtocol (
359 IN BOOLEAN EmuBusDriver,
360 OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL
361 )
362{
363 return GetNextThunkProtocol (EmuBusDriver, Instance);
364}
365
366
367EMU_THUNK_PROTOCOL gEmuThunkProtocol = {
368 GasketSecWriteStdErr,
7e284acb 369 GasketSecConfigStdIn,
370 GasketSecWriteStdOut,
371 GasketSecReadStdIn,
372 GasketSecPollStdIn,
949f388f 373 GasketSecPeCoffGetEntryPoint,
374 GasketSecPeCoffRelocateImageExtraAction,
375 GasketSecPeCoffUnloadImageExtraAction,
376 GasketSecEnableInterrupt,
377 GasketSecDisableInterrupt,
378 GasketQueryPerformanceFrequency,
379 GasketQueryPerformanceCounter,
380 GasketSecSleep,
57c7d70f 381 GasketSecCpuSleep,
949f388f 382 GasketSecExit,
383 GasketSecGetTime,
384 GasketSecSetTime,
385 GasketSecSetTimer,
386 GasketSecGetNextProtocol
387};
388
389
390VOID
391SecInitThunkProtocol (
392 VOID
393 )
394{
395 // timezone and daylight lib globals depend on tzset be called 1st.
396 tzset ();
397}
398