]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Unix/Host/EmuThunk.c
BaseTools: Fix GenFds issue to wrongly get file without postfix.
[mirror_edk2.git] / EmulatorPkg / Unix / Host / EmuThunk.c
CommitLineData
949f388f 1/*++ @file
d18d8a1d 2 Since the SEC is the only program in our emulation we
949f388f 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>
d18d8a1d 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.
949f388f 21
22**/
23
59ad461d 24#include "Host.h"
949f388f 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;
d18d8a1d 51
7e284acb 52 Return = write (STDERR_FILENO, (const void *)Buffer, (size_t)NumberOfBytes);
d18d8a1d 53
949f388f 54 return (Return == -1) ? 0 : Return;
55}
56
57
7e284acb 58EFI_STATUS
59SecConfigStdIn (
60 VOID
61 )
62{
63 struct termios tty;
d18d8a1d 64
7e284acb 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);
d18d8a1d 71
7e284acb 72// setvbuf (STDIN_FILENO, NULL, _IONBF, 0);
d18d8a1d 73
7e284acb 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;
d18d8a1d 85
7e284acb 86 Return = write (STDOUT_FILENO, (const void *)Buffer, (size_t)NumberOfBytes);
d18d8a1d 87
7e284acb 88 return (Return == -1) ? 0 : Return;
89}
90
91UINTN
92SecReadStdIn (
93 IN UINT8 *Buffer,
94 IN UINTN NumberOfBytes
95 )
96{
97 ssize_t Return;
d18d8a1d 98
7e284acb 99 Return = read (STDIN_FILENO, Buffer, (size_t)NumberOfBytes);
d18d8a1d 100
7e284acb 101 return (Return == -1) ? 0 : Return;
102}
103
104BOOLEAN
105SecPollStdIn (
106 VOID
107 )
108{
109 int Result;
110 int Bytes;
d18d8a1d 111
7e284acb 112 Result = ioctl (STDIN_FILENO, FIONREAD, &Bytes);
113 if (Result == -1) {
114 return FALSE;
115 }
d18d8a1d 116
7e284acb 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
1d7ac5a6 129VOID *
130SecValloc (
131 IN UINTN Size
132 )
133{
134 return valloc ((size_t)Size);
135}
136
137BOOLEAN
c2175068 138SecFree (
139 IN VOID *Ptr
140 )
141{
1d7ac5a6 142 if (EfiSystemMemoryRange (Ptr)) {
143 // If an address range is in the EFI memory map it was alloced via EFI.
144 // So don't free those ranges and let the caller know.
145 return FALSE;
146 }
d18d8a1d 147
c2175068 148 free (Ptr);
1d7ac5a6 149 return TRUE;
c2175068 150}
151
949f388f 152
153void
154settimer_handler (int sig)
155{
156 struct timeval timeval;
157 UINT64 delta;
158
159 gettimeofday (&timeval, NULL);
160 delta = ((UINT64)timeval.tv_sec * 1000) + (timeval.tv_usec / 1000)
d18d8a1d 161 - ((UINT64)settimer_timeval.tv_sec * 1000)
949f388f 162 - (settimer_timeval.tv_usec / 1000);
163 settimer_timeval = timeval;
d18d8a1d 164
949f388f 165 if (settimer_callback) {
166 ReverseGasketUint64 (settimer_callback, delta);
167 }
168}
169
170VOID
171SecSetTimer (
172 IN UINT64 PeriodMs,
173 IN EMU_SET_TIMER_CALLBACK CallBack
174 )
175{
176 struct itimerval timerval;
177 UINT32 remainder;
178
179 if (!settimer_initialized) {
180 struct sigaction act;
181
182 settimer_initialized = 1;
183 act.sa_handler = settimer_handler;
184 act.sa_flags = 0;
185 sigemptyset (&act.sa_mask);
186 gEmulatorInterruptEnabled = TRUE;
187 if (sigaction (SIGALRM, &act, NULL) != 0) {
188 printf ("SetTimer: sigaction error %s\n", strerror (errno));
189 }
190 if (gettimeofday (&settimer_timeval, NULL) != 0) {
191 printf ("SetTimer: gettimeofday error %s\n", strerror (errno));
192 }
193 }
194 timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000);
195 DivU64x32Remainder(PeriodMs, 1000, &remainder);
196 timerval.it_value.tv_usec = remainder * 1000;
197 timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000);
198 timerval.it_interval = timerval.it_value;
d18d8a1d 199
949f388f 200 if (setitimer (ITIMER_REAL, &timerval, NULL) != 0) {
201 printf ("SetTimer: setitimer error %s\n", strerror (errno));
202 }
203 settimer_callback = CallBack;
204}
205
206
207VOID
208SecEnableInterrupt (
209 VOID
210 )
211{
212 sigset_t sigset;
213
214 gEmulatorInterruptEnabled = TRUE;
d18d8a1d 215 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
949f388f 216 // by enabling/disabling SIGALRM.
217 sigemptyset (&sigset);
218 sigaddset (&sigset, SIGALRM);
219 pthread_sigmask (SIG_UNBLOCK, &sigset, NULL);
220}
221
222
223VOID
224SecDisableInterrupt (
225 VOID
226 )
227{
228 sigset_t sigset;
229
d18d8a1d 230 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
949f388f 231 // by enabling/disabling SIGALRM.
232 sigemptyset (&sigset);
233 sigaddset (&sigset, SIGALRM);
234 pthread_sigmask (SIG_BLOCK, &sigset, NULL);
235 gEmulatorInterruptEnabled = FALSE;
236}
237
238
239BOOLEAN
240SecInterruptEanbled (void)
241{
242 return gEmulatorInterruptEnabled;
243}
244
245
246UINT64
247QueryPerformanceFrequency (
248 VOID
249 )
250{
251 // Hard code to nanoseconds
252 return 1000000000ULL;
253}
254
255UINT64
256QueryPerformanceCounter (
257 VOID
258 )
259{
260#if __APPLE__
261 UINT64 Start;
5b484a25 262 static mach_timebase_info_data_t sTimebaseInfo;
263
949f388f 264
265 Start = mach_absolute_time ();
d18d8a1d 266
949f388f 267 // Convert to nanoseconds.
268
5b484a25 269 // If this is the first time we've run, get the timebase.
270 // We can use denom == 0 to indicate that sTimebaseInfo is
271 // uninitialised because it makes no sense to have a zero
272 // denominator is a fraction.
273
274 if ( sTimebaseInfo.denom == 0 ) {
275 (void) mach_timebase_info(&sTimebaseInfo);
276 }
277
278 // Do the maths. We hope that the multiplication doesn't
279 // overflow; the price you pay for working in fixed point.
949f388f 280
5b484a25 281 return (Start * sTimebaseInfo.numer) / sTimebaseInfo.denom;
949f388f 282#else
283 // Need to figure out what to do for Linux?
284 return 0;
285#endif
286}
d18d8a1d 287
949f388f 288
289
290VOID
291SecSleep (
1ef41207 292 IN UINT64 Nanoseconds
949f388f 293 )
294{
295 struct timespec rq, rm;
296 struct timeval start, end;
297 unsigned long MicroSec;
d18d8a1d 298
54e0b04c 299 rq.tv_sec = DivU64x32 (Nanoseconds, 1000000000);
300 rq.tv_nsec = ModU64x32 (Nanoseconds, 1000000000);
949f388f 301
302 //
d18d8a1d 303 // nanosleep gets interrupted by our timer tic.
949f388f 304 // we need to track wall clock time or we will stall for way too long
305 //
306 gettimeofday (&start, NULL);
307 end.tv_sec = start.tv_sec + rq.tv_sec;
308 MicroSec = (start.tv_usec + rq.tv_nsec/1000);
309 end.tv_usec = MicroSec % 1000000;
310 if (MicroSec > 1000000) {
311 end.tv_sec++;
312 }
313
314 while (nanosleep (&rq, &rm) == -1) {
315 if (errno != EINTR) {
316 break;
317 }
318 gettimeofday (&start, NULL);
319 if (start.tv_sec > end.tv_sec) {
320 break;
321 } if ((start.tv_sec == end.tv_sec) && (start.tv_usec > end.tv_usec)) {
322 break;
323 }
324 rq = rm;
d18d8a1d 325 }
949f388f 326}
327
57c7d70f 328
329VOID
330SecCpuSleep (
331 VOID
332 )
333{
334 struct timespec rq, rm;
335
336 // nanosleep gets interrupted by the timer tic
337 rq.tv_sec = 1;
338 rq.tv_nsec = 0;
d18d8a1d 339
57c7d70f 340 nanosleep (&rq, &rm);
341}
342
343
949f388f 344VOID
345SecExit (
346 UINTN Status
347 )
348{
349 exit (Status);
350}
351
352
353VOID
354SecGetTime (
355 OUT EFI_TIME *Time,
356 OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
357 )
358{
359 struct tm *tm;
360 time_t t;
361
362 t = time (NULL);
363 tm = localtime (&t);
364
365 Time->Year = 1900 + tm->tm_year;
366 Time->Month = tm->tm_mon + 1;
367 Time->Day = tm->tm_mday;
368 Time->Hour = tm->tm_hour;
369 Time->Minute = tm->tm_min;
370 Time->Second = tm->tm_sec;
371 Time->Nanosecond = 0;
372 Time->TimeZone = timezone;
373 Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0)
374 | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0);
d18d8a1d 375
949f388f 376 if (Capabilities != NULL) {
377 Capabilities->Resolution = 1;
378 Capabilities->Accuracy = 50000000;
379 Capabilities->SetsToZero = FALSE;
380 }
381}
382
383
384
385VOID
386SecSetTime (
387 IN EFI_TIME *Time
388 )
389{
390 // Don't change the time on the system
391 // We could save delta to localtime() and have SecGetTime adjust return values?
392 return;
393}
394
395
396EFI_STATUS
397SecGetNextProtocol (
398 IN BOOLEAN EmuBusDriver,
399 OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL
400 )
401{
402 return GetNextThunkProtocol (EmuBusDriver, Instance);
403}
404
405
406EMU_THUNK_PROTOCOL gEmuThunkProtocol = {
407 GasketSecWriteStdErr,
7e284acb 408 GasketSecConfigStdIn,
409 GasketSecWriteStdOut,
410 GasketSecReadStdIn,
411 GasketSecPollStdIn,
c2175068 412 GasketSecMalloc,
1d7ac5a6 413 GasketSecValloc,
c2175068 414 GasketSecFree,
949f388f 415 GasketSecPeCoffGetEntryPoint,
416 GasketSecPeCoffRelocateImageExtraAction,
417 GasketSecPeCoffUnloadImageExtraAction,
418 GasketSecEnableInterrupt,
419 GasketSecDisableInterrupt,
420 GasketQueryPerformanceFrequency,
421 GasketQueryPerformanceCounter,
422 GasketSecSleep,
57c7d70f 423 GasketSecCpuSleep,
949f388f 424 GasketSecExit,
d18d8a1d 425 GasketSecGetTime,
949f388f 426 GasketSecSetTime,
d18d8a1d 427 GasketSecSetTimer,
949f388f 428 GasketSecGetNextProtocol
429};
430
431
432VOID
433SecInitThunkProtocol (
434 VOID
435 )
436{
437 // timezone and daylight lib globals depend on tzset be called 1st.
438 tzset ();
439}
440