]> git.proxmox.com Git - mirror_edk2.git/blame - InOsEmuPkg/Unix/Sec/EmuThunk.c
Add support for SerialPortLib that maps into POSIX StdIn and StdOut. Add a device...
[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 (
253 IN UINT64 Milliseconds
254 )
255{
256 struct timespec rq, rm;
257 struct timeval start, end;
258 unsigned long MicroSec;
259
260 rq.tv_sec = Milliseconds / 1000;
261 rq.tv_nsec = (Milliseconds % 1000) * 1000000;
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
289VOID
290SecExit (
291 UINTN Status
292 )
293{
294 exit (Status);
295}
296
297
298VOID
299SecGetTime (
300 OUT EFI_TIME *Time,
301 OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
302 )
303{
304 struct tm *tm;
305 time_t t;
306
307 t = time (NULL);
308 tm = localtime (&t);
309
310 Time->Year = 1900 + tm->tm_year;
311 Time->Month = tm->tm_mon + 1;
312 Time->Day = tm->tm_mday;
313 Time->Hour = tm->tm_hour;
314 Time->Minute = tm->tm_min;
315 Time->Second = tm->tm_sec;
316 Time->Nanosecond = 0;
317 Time->TimeZone = timezone;
318 Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0)
319 | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0);
320
321 if (Capabilities != NULL) {
322 Capabilities->Resolution = 1;
323 Capabilities->Accuracy = 50000000;
324 Capabilities->SetsToZero = FALSE;
325 }
326}
327
328
329
330VOID
331SecSetTime (
332 IN EFI_TIME *Time
333 )
334{
335 // Don't change the time on the system
336 // We could save delta to localtime() and have SecGetTime adjust return values?
337 return;
338}
339
340
341EFI_STATUS
342SecGetNextProtocol (
343 IN BOOLEAN EmuBusDriver,
344 OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL
345 )
346{
347 return GetNextThunkProtocol (EmuBusDriver, Instance);
348}
349
350
351EMU_THUNK_PROTOCOL gEmuThunkProtocol = {
352 GasketSecWriteStdErr,
7e284acb 353 GasketSecConfigStdIn,
354 GasketSecWriteStdOut,
355 GasketSecReadStdIn,
356 GasketSecPollStdIn,
949f388f 357 GasketSecPeCoffGetEntryPoint,
358 GasketSecPeCoffRelocateImageExtraAction,
359 GasketSecPeCoffUnloadImageExtraAction,
360 GasketSecEnableInterrupt,
361 GasketSecDisableInterrupt,
362 GasketQueryPerformanceFrequency,
363 GasketQueryPerformanceCounter,
364 GasketSecSleep,
365 GasketSecExit,
366 GasketSecGetTime,
367 GasketSecSetTime,
368 GasketSecSetTimer,
369 GasketSecGetNextProtocol
370};
371
372
373VOID
374SecInitThunkProtocol (
375 VOID
376 )
377{
378 // timezone and daylight lib globals depend on tzset be called 1st.
379 tzset ();
380}
381