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);
123 settimer_handler (int sig
)
125 struct timeval timeval
;
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
;
134 if (settimer_callback
) {
135 ReverseGasketUint64 (settimer_callback
, delta
);
142 IN EMU_SET_TIMER_CALLBACK CallBack
145 struct itimerval timerval
;
148 if (!settimer_initialized
) {
149 struct sigaction act
;
151 settimer_initialized
= 1;
152 act
.sa_handler
= settimer_handler
;
154 sigemptyset (&act
.sa_mask
);
155 gEmulatorInterruptEnabled
= TRUE
;
156 if (sigaction (SIGALRM
, &act
, NULL
) != 0) {
157 printf ("SetTimer: sigaction error %s\n", strerror (errno
));
159 if (gettimeofday (&settimer_timeval
, NULL
) != 0) {
160 printf ("SetTimer: gettimeofday error %s\n", strerror (errno
));
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
;
169 if (setitimer (ITIMER_REAL
, &timerval
, NULL
) != 0) {
170 printf ("SetTimer: setitimer error %s\n", strerror (errno
));
172 settimer_callback
= CallBack
;
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
);
193 SecDisableInterrupt (
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
;
209 SecInterruptEanbled (void)
211 return gEmulatorInterruptEnabled
;
216 QueryPerformanceFrequency (
220 // Hard code to nanoseconds
221 return 1000000000ULL;
225 QueryPerformanceCounter (
231 Nanoseconds elapsedNano
;
233 Start
= mach_absolute_time ();
235 // Convert to nanoseconds.
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
);
242 return *(uint64_t *) &elapsedNano
;
244 // Need to figure out what to do for Linux?
253 IN UINT64 Nanoseconds
256 struct timespec rq
, rm
;
257 struct timeval start
, end
;
258 unsigned long MicroSec
;
260 rq
.tv_sec
= DivU64x32 (Nanoseconds
, 1000000000);
261 rq
.tv_nsec
= ModU64x32 (Nanoseconds
, 1000000000);
264 // nanosleep gets interrupted by our timer tic.
265 // we need to track wall clock time or we will stall for way too long
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) {
275 while (nanosleep (&rq
, &rm
) == -1) {
276 if (errno
!= EINTR
) {
279 gettimeofday (&start
, NULL
);
280 if (start
.tv_sec
> end
.tv_sec
) {
282 } if ((start
.tv_sec
== end
.tv_sec
) && (start
.tv_usec
> end
.tv_usec
)) {
295 struct timespec rq
, rm
;
297 // nanosleep gets interrupted by the timer tic
301 nanosleep (&rq
, &rm
);
317 OUT EFI_TIME_CAPABILITIES
*Capabilities OPTIONAL
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);
337 if (Capabilities
!= NULL
) {
338 Capabilities
->Resolution
= 1;
339 Capabilities
->Accuracy
= 50000000;
340 Capabilities
->SetsToZero
= FALSE
;
351 // Don't change the time on the system
352 // We could save delta to localtime() and have SecGetTime adjust return values?
359 IN BOOLEAN EmuBusDriver
,
360 OUT EMU_IO_THUNK_PROTOCOL
**Instance OPTIONAL
363 return GetNextThunkProtocol (EmuBusDriver
, Instance
);
367 EMU_THUNK_PROTOCOL gEmuThunkProtocol
= {
368 GasketSecWriteStdErr
,
369 GasketSecConfigStdIn
,
370 GasketSecWriteStdOut
,
373 GasketSecPeCoffGetEntryPoint
,
374 GasketSecPeCoffRelocateImageExtraAction
,
375 GasketSecPeCoffUnloadImageExtraAction
,
376 GasketSecEnableInterrupt
,
377 GasketSecDisableInterrupt
,
378 GasketQueryPerformanceFrequency
,
379 GasketQueryPerformanceCounter
,
386 GasketSecGetNextProtocol
391 SecInitThunkProtocol (
395 // timezone and daylight lib globals depend on tzset be called 1st.