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.
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.
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
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.
27 #define DebugAssert _Mangle__DebugAssert
30 #include <CoreServices/CoreServices.h>
31 #include <mach/mach.h>
32 #include <mach/mach_time.h>
37 int settimer_initialized
;
38 struct timeval settimer_timeval
;
39 void (*settimer_callback
)(UINT64 delta
);
41 BOOLEAN gEmulatorInterruptEnabled
= FALSE
;
47 IN UINTN NumberOfBytes
52 Return
= write (STDERR_FILENO
, (const void *)Buffer
, (size_t)NumberOfBytes
);
54 return (Return
== -1) ? 0 : Return
;
66 // Need to turn off line buffering, ECHO, and make it unbuffered.
68 tcgetattr (STDIN_FILENO
, &tty
);
69 tty
.c_lflag
&= ~(ICANON
| ECHO
);
70 tcsetattr (STDIN_FILENO
, TCSANOW
, &tty
);
72 // setvbuf (STDIN_FILENO, NULL, _IONBF, 0);
74 // now ioctl FIONREAD will do what we need
81 IN UINTN NumberOfBytes
86 Return
= write (STDOUT_FILENO
, (const void *)Buffer
, (size_t)NumberOfBytes
);
88 return (Return
== -1) ? 0 : Return
;
94 IN UINTN NumberOfBytes
99 Return
= read (STDIN_FILENO
, Buffer
, (size_t)NumberOfBytes
);
101 return (Return
== -1) ? 0 : Return
;
112 Result
= ioctl (STDIN_FILENO
, FIONREAD
, &Bytes
);
117 return (BOOLEAN
)(Bytes
> 0);
126 return malloc ((size_t)Size
);
134 return valloc ((size_t)Size
);
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.
154 settimer_handler (int sig
)
156 struct timeval timeval
;
159 gettimeofday (&timeval
, NULL
);
160 delta
= ((UINT64
)timeval
.tv_sec
* 1000) + (timeval
.tv_usec
/ 1000)
161 - ((UINT64
)settimer_timeval
.tv_sec
* 1000)
162 - (settimer_timeval
.tv_usec
/ 1000);
163 settimer_timeval
= timeval
;
165 if (settimer_callback
) {
166 ReverseGasketUint64 (settimer_callback
, delta
);
173 IN EMU_SET_TIMER_CALLBACK CallBack
176 struct itimerval timerval
;
179 if (!settimer_initialized
) {
180 struct sigaction act
;
182 settimer_initialized
= 1;
183 act
.sa_handler
= settimer_handler
;
185 sigemptyset (&act
.sa_mask
);
186 gEmulatorInterruptEnabled
= TRUE
;
187 if (sigaction (SIGALRM
, &act
, NULL
) != 0) {
188 printf ("SetTimer: sigaction error %s\n", strerror (errno
));
190 if (gettimeofday (&settimer_timeval
, NULL
) != 0) {
191 printf ("SetTimer: gettimeofday error %s\n", strerror (errno
));
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
;
200 if (setitimer (ITIMER_REAL
, &timerval
, NULL
) != 0) {
201 printf ("SetTimer: setitimer error %s\n", strerror (errno
));
203 settimer_callback
= CallBack
;
214 gEmulatorInterruptEnabled
= TRUE
;
215 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
216 // by enabling/disabling SIGALRM.
217 sigemptyset (&sigset
);
218 sigaddset (&sigset
, SIGALRM
);
219 pthread_sigmask (SIG_UNBLOCK
, &sigset
, NULL
);
224 SecDisableInterrupt (
230 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
231 // by enabling/disabling SIGALRM.
232 sigemptyset (&sigset
);
233 sigaddset (&sigset
, SIGALRM
);
234 pthread_sigmask (SIG_BLOCK
, &sigset
, NULL
);
235 gEmulatorInterruptEnabled
= FALSE
;
240 SecInterruptEanbled (void)
242 return gEmulatorInterruptEnabled
;
247 QueryPerformanceFrequency (
251 // Hard code to nanoseconds
252 return 1000000000ULL;
256 QueryPerformanceCounter (
262 static mach_timebase_info_data_t sTimebaseInfo
;
265 Start
= mach_absolute_time ();
267 // Convert to nanoseconds.
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.
274 if ( sTimebaseInfo
.denom
== 0 ) {
275 (void) mach_timebase_info(&sTimebaseInfo
);
278 // Do the maths. We hope that the multiplication doesn't
279 // overflow; the price you pay for working in fixed point.
281 return (Start
* sTimebaseInfo
.numer
) / sTimebaseInfo
.denom
;
283 // Need to figure out what to do for Linux?
292 IN UINT64 Nanoseconds
295 struct timespec rq
, rm
;
296 struct timeval start
, end
;
297 unsigned long MicroSec
;
299 rq
.tv_sec
= DivU64x32 (Nanoseconds
, 1000000000);
300 rq
.tv_nsec
= ModU64x32 (Nanoseconds
, 1000000000);
303 // nanosleep gets interrupted by our timer tic.
304 // we need to track wall clock time or we will stall for way too long
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) {
314 while (nanosleep (&rq
, &rm
) == -1) {
315 if (errno
!= EINTR
) {
318 gettimeofday (&start
, NULL
);
319 if (start
.tv_sec
> end
.tv_sec
) {
321 } if ((start
.tv_sec
== end
.tv_sec
) && (start
.tv_usec
> end
.tv_usec
)) {
334 struct timespec rq
, rm
;
336 // nanosleep gets interrupted by the timer tic
340 nanosleep (&rq
, &rm
);
356 OUT EFI_TIME_CAPABILITIES
*Capabilities OPTIONAL
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);
376 if (Capabilities
!= NULL
) {
377 Capabilities
->Resolution
= 1;
378 Capabilities
->Accuracy
= 50000000;
379 Capabilities
->SetsToZero
= FALSE
;
390 // Don't change the time on the system
391 // We could save delta to localtime() and have SecGetTime adjust return values?
398 IN BOOLEAN EmuBusDriver
,
399 OUT EMU_IO_THUNK_PROTOCOL
**Instance OPTIONAL
402 return GetNextThunkProtocol (EmuBusDriver
, Instance
);
406 EMU_THUNK_PROTOCOL gEmuThunkProtocol
= {
407 GasketSecWriteStdErr
,
408 GasketSecConfigStdIn
,
409 GasketSecWriteStdOut
,
415 GasketSecPeCoffGetEntryPoint
,
416 GasketSecPeCoffRelocateImageExtraAction
,
417 GasketSecPeCoffUnloadImageExtraAction
,
418 GasketSecEnableInterrupt
,
419 GasketSecDisableInterrupt
,
420 GasketQueryPerformanceFrequency
,
421 GasketQueryPerformanceCounter
,
428 GasketSecGetNextProtocol
433 SecInitThunkProtocol (
437 // timezone and daylight lib globals depend on tzset be called 1st.