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 (1, (const void *)Buffer
, (size_t)NumberOfBytes
);
54 return (Return
== -1) ? 0 : Return
;
60 settimer_handler (int sig
)
62 struct timeval timeval
;
65 gettimeofday (&timeval
, NULL
);
66 delta
= ((UINT64
)timeval
.tv_sec
* 1000) + (timeval
.tv_usec
/ 1000)
67 - ((UINT64
)settimer_timeval
.tv_sec
* 1000)
68 - (settimer_timeval
.tv_usec
/ 1000);
69 settimer_timeval
= timeval
;
71 if (settimer_callback
) {
72 ReverseGasketUint64 (settimer_callback
, delta
);
79 IN EMU_SET_TIMER_CALLBACK CallBack
82 struct itimerval timerval
;
85 if (!settimer_initialized
) {
88 settimer_initialized
= 1;
89 act
.sa_handler
= settimer_handler
;
91 sigemptyset (&act
.sa_mask
);
92 gEmulatorInterruptEnabled
= TRUE
;
93 if (sigaction (SIGALRM
, &act
, NULL
) != 0) {
94 printf ("SetTimer: sigaction error %s\n", strerror (errno
));
96 if (gettimeofday (&settimer_timeval
, NULL
) != 0) {
97 printf ("SetTimer: gettimeofday error %s\n", strerror (errno
));
100 timerval
.it_value
.tv_sec
= DivU64x32(PeriodMs
, 1000);
101 DivU64x32Remainder(PeriodMs
, 1000, &remainder
);
102 timerval
.it_value
.tv_usec
= remainder
* 1000;
103 timerval
.it_value
.tv_sec
= DivU64x32(PeriodMs
, 1000);
104 timerval
.it_interval
= timerval
.it_value
;
106 if (setitimer (ITIMER_REAL
, &timerval
, NULL
) != 0) {
107 printf ("SetTimer: setitimer error %s\n", strerror (errno
));
109 settimer_callback
= CallBack
;
120 gEmulatorInterruptEnabled
= TRUE
;
121 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
122 // by enabling/disabling SIGALRM.
123 sigemptyset (&sigset
);
124 sigaddset (&sigset
, SIGALRM
);
125 pthread_sigmask (SIG_UNBLOCK
, &sigset
, NULL
);
130 SecDisableInterrupt (
136 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
137 // by enabling/disabling SIGALRM.
138 sigemptyset (&sigset
);
139 sigaddset (&sigset
, SIGALRM
);
140 pthread_sigmask (SIG_BLOCK
, &sigset
, NULL
);
141 gEmulatorInterruptEnabled
= FALSE
;
146 SecInterruptEanbled (void)
148 return gEmulatorInterruptEnabled
;
153 QueryPerformanceFrequency (
157 // Hard code to nanoseconds
158 return 1000000000ULL;
162 QueryPerformanceCounter (
168 Nanoseconds elapsedNano
;
170 Start
= mach_absolute_time ();
172 // Convert to nanoseconds.
174 // Have to do some pointer fun because AbsoluteToNanoseconds
175 // works in terms of UnsignedWide, which is a structure rather
176 // than a proper 64-bit integer.
177 elapsedNano
= AbsoluteToNanoseconds (*(AbsoluteTime
*) &Start
);
179 return *(uint64_t *) &elapsedNano
;
181 // Need to figure out what to do for Linux?
190 IN UINT64 Milliseconds
193 struct timespec rq
, rm
;
194 struct timeval start
, end
;
195 unsigned long MicroSec
;
197 rq
.tv_sec
= Milliseconds
/ 1000;
198 rq
.tv_nsec
= (Milliseconds
% 1000) * 1000000;
201 // nanosleep gets interrupted by our timer tic.
202 // we need to track wall clock time or we will stall for way too long
204 gettimeofday (&start
, NULL
);
205 end
.tv_sec
= start
.tv_sec
+ rq
.tv_sec
;
206 MicroSec
= (start
.tv_usec
+ rq
.tv_nsec
/1000);
207 end
.tv_usec
= MicroSec
% 1000000;
208 if (MicroSec
> 1000000) {
212 while (nanosleep (&rq
, &rm
) == -1) {
213 if (errno
!= EINTR
) {
216 gettimeofday (&start
, NULL
);
217 if (start
.tv_sec
> end
.tv_sec
) {
219 } if ((start
.tv_sec
== end
.tv_sec
) && (start
.tv_usec
> end
.tv_usec
)) {
238 OUT EFI_TIME_CAPABILITIES
*Capabilities OPTIONAL
247 Time
->Year
= 1900 + tm
->tm_year
;
248 Time
->Month
= tm
->tm_mon
+ 1;
249 Time
->Day
= tm
->tm_mday
;
250 Time
->Hour
= tm
->tm_hour
;
251 Time
->Minute
= tm
->tm_min
;
252 Time
->Second
= tm
->tm_sec
;
253 Time
->Nanosecond
= 0;
254 Time
->TimeZone
= timezone
;
255 Time
->Daylight
= (daylight
? EFI_TIME_ADJUST_DAYLIGHT
: 0)
256 | (tm
->tm_isdst
> 0 ? EFI_TIME_IN_DAYLIGHT
: 0);
258 if (Capabilities
!= NULL
) {
259 Capabilities
->Resolution
= 1;
260 Capabilities
->Accuracy
= 50000000;
261 Capabilities
->SetsToZero
= FALSE
;
272 // Don't change the time on the system
273 // We could save delta to localtime() and have SecGetTime adjust return values?
280 IN BOOLEAN EmuBusDriver
,
281 OUT EMU_IO_THUNK_PROTOCOL
**Instance OPTIONAL
284 return GetNextThunkProtocol (EmuBusDriver
, Instance
);
288 EMU_THUNK_PROTOCOL gEmuThunkProtocol
= {
289 GasketSecWriteStdErr
,
290 GasketSecPeCoffGetEntryPoint
,
291 GasketSecPeCoffRelocateImageExtraAction
,
292 GasketSecPeCoffUnloadImageExtraAction
,
293 GasketSecEnableInterrupt
,
294 GasketSecDisableInterrupt
,
295 GasketQueryPerformanceFrequency
,
296 GasketQueryPerformanceCounter
,
302 GasketSecGetNextProtocol
307 SecInitThunkProtocol (
311 // timezone and daylight lib globals depend on tzset be called 1st.