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 Nanoseconds elapsedNano
;
264 Start
= mach_absolute_time ();
266 // Convert to nanoseconds.
268 // Have to do some pointer fun because AbsoluteToNanoseconds
269 // works in terms of UnsignedWide, which is a structure rather
270 // than a proper 64-bit integer.
271 elapsedNano
= AbsoluteToNanoseconds (*(AbsoluteTime
*) &Start
);
273 return *(uint64_t *) &elapsedNano
;
275 // Need to figure out what to do for Linux?
284 IN UINT64 Nanoseconds
287 struct timespec rq
, rm
;
288 struct timeval start
, end
;
289 unsigned long MicroSec
;
291 rq
.tv_sec
= DivU64x32 (Nanoseconds
, 1000000000);
292 rq
.tv_nsec
= ModU64x32 (Nanoseconds
, 1000000000);
295 // nanosleep gets interrupted by our timer tic.
296 // we need to track wall clock time or we will stall for way too long
298 gettimeofday (&start
, NULL
);
299 end
.tv_sec
= start
.tv_sec
+ rq
.tv_sec
;
300 MicroSec
= (start
.tv_usec
+ rq
.tv_nsec
/1000);
301 end
.tv_usec
= MicroSec
% 1000000;
302 if (MicroSec
> 1000000) {
306 while (nanosleep (&rq
, &rm
) == -1) {
307 if (errno
!= EINTR
) {
310 gettimeofday (&start
, NULL
);
311 if (start
.tv_sec
> end
.tv_sec
) {
313 } if ((start
.tv_sec
== end
.tv_sec
) && (start
.tv_usec
> end
.tv_usec
)) {
326 struct timespec rq
, rm
;
328 // nanosleep gets interrupted by the timer tic
332 nanosleep (&rq
, &rm
);
348 OUT EFI_TIME_CAPABILITIES
*Capabilities OPTIONAL
357 Time
->Year
= 1900 + tm
->tm_year
;
358 Time
->Month
= tm
->tm_mon
+ 1;
359 Time
->Day
= tm
->tm_mday
;
360 Time
->Hour
= tm
->tm_hour
;
361 Time
->Minute
= tm
->tm_min
;
362 Time
->Second
= tm
->tm_sec
;
363 Time
->Nanosecond
= 0;
364 Time
->TimeZone
= timezone
;
365 Time
->Daylight
= (daylight
? EFI_TIME_ADJUST_DAYLIGHT
: 0)
366 | (tm
->tm_isdst
> 0 ? EFI_TIME_IN_DAYLIGHT
: 0);
368 if (Capabilities
!= NULL
) {
369 Capabilities
->Resolution
= 1;
370 Capabilities
->Accuracy
= 50000000;
371 Capabilities
->SetsToZero
= FALSE
;
382 // Don't change the time on the system
383 // We could save delta to localtime() and have SecGetTime adjust return values?
390 IN BOOLEAN EmuBusDriver
,
391 OUT EMU_IO_THUNK_PROTOCOL
**Instance OPTIONAL
394 return GetNextThunkProtocol (EmuBusDriver
, Instance
);
398 EMU_THUNK_PROTOCOL gEmuThunkProtocol
= {
399 GasketSecWriteStdErr
,
400 GasketSecConfigStdIn
,
401 GasketSecWriteStdOut
,
407 GasketSecPeCoffGetEntryPoint
,
408 GasketSecPeCoffRelocateImageExtraAction
,
409 GasketSecPeCoffUnloadImageExtraAction
,
410 GasketSecEnableInterrupt
,
411 GasketSecDisableInterrupt
,
412 GasketQueryPerformanceFrequency
,
413 GasketQueryPerformanceCounter
,
420 GasketSecGetNextProtocol
425 SecInitThunkProtocol (
429 // timezone and daylight lib globals depend on tzset be called 1st.