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 initialized with the members at the end being
10 set to zero. This is bad as jumping to zero will crash.
12 Copyright (c) 2004 - 2019, Intel Corporation. All rights reserved.<BR>
13 Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
14 SPDX-License-Identifier: BSD-2-Clause-Patent
21 #define DebugAssert _Mangle__DebugAssert
24 #include <CoreServices/CoreServices.h>
25 #include <mach/mach.h>
26 #include <mach/mach_time.h>
31 int settimer_initialized
;
32 struct timeval settimer_timeval
;
33 UINTN settimer_callback
= 0;
35 BOOLEAN gEmulatorInterruptEnabled
= FALSE
;
40 IN UINTN NumberOfBytes
45 Return
= write (STDERR_FILENO
, (const void *)Buffer
, (size_t)NumberOfBytes
);
47 return (Return
== -1) ? 0 : Return
;
58 // Need to turn off line buffering, ECHO, and make it unbuffered.
60 tcgetattr (STDIN_FILENO
, &tty
);
61 tty
.c_lflag
&= ~(ICANON
| ECHO
);
62 tcsetattr (STDIN_FILENO
, TCSANOW
, &tty
);
64 // setvbuf (STDIN_FILENO, NULL, _IONBF, 0);
66 // now ioctl FIONREAD will do what we need
73 IN UINTN NumberOfBytes
78 Return
= write (STDOUT_FILENO
, (const void *)Buffer
, (size_t)NumberOfBytes
);
80 return (Return
== -1) ? 0 : Return
;
86 IN UINTN NumberOfBytes
91 Return
= read (STDIN_FILENO
, Buffer
, (size_t)NumberOfBytes
);
93 return (Return
== -1) ? 0 : Return
;
104 Result
= ioctl (STDIN_FILENO
, FIONREAD
, &Bytes
);
109 return (BOOLEAN
)(Bytes
> 0);
117 return malloc ((size_t)Size
);
125 return valloc ((size_t)Size
);
133 if (EfiSystemMemoryRange (Ptr
)) {
134 // If an address range is in the EFI memory map it was alloced via EFI.
135 // So don't free those ranges and let the caller know.
148 struct timeval timeval
;
151 gettimeofday (&timeval
, NULL
);
152 delta
= ((UINT64
)timeval
.tv_sec
* 1000) + (timeval
.tv_usec
/ 1000)
153 - ((UINT64
)settimer_timeval
.tv_sec
* 1000)
154 - (settimer_timeval
.tv_usec
/ 1000);
155 settimer_timeval
= timeval
;
157 if (settimer_callback
) {
158 ReverseGasketUint64 (settimer_callback
, delta
);
165 IN EMU_SET_TIMER_CALLBACK CallBack
168 struct itimerval timerval
;
171 if (!settimer_initialized
) {
172 struct sigaction act
;
174 settimer_initialized
= 1;
175 act
.sa_handler
= settimer_handler
;
177 sigemptyset (&act
.sa_mask
);
178 gEmulatorInterruptEnabled
= TRUE
;
179 if (sigaction (SIGALRM
, &act
, NULL
) != 0) {
180 printf ("SetTimer: sigaction error %s\n", strerror (errno
));
183 if (gettimeofday (&settimer_timeval
, NULL
) != 0) {
184 printf ("SetTimer: gettimeofday error %s\n", strerror (errno
));
188 timerval
.it_value
.tv_sec
= DivU64x32 (PeriodMs
, 1000);
189 DivU64x32Remainder (PeriodMs
, 1000, &remainder
);
190 timerval
.it_value
.tv_usec
= remainder
* 1000;
191 timerval
.it_value
.tv_sec
= DivU64x32 (PeriodMs
, 1000);
192 timerval
.it_interval
= timerval
.it_value
;
194 if (setitimer (ITIMER_REAL
, &timerval
, NULL
) != 0) {
195 printf ("SetTimer: setitimer error %s\n", strerror (errno
));
198 settimer_callback
= (UINTN
)CallBack
;
208 gEmulatorInterruptEnabled
= TRUE
;
209 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
210 // by enabling/disabling SIGALRM.
211 sigemptyset (&sigset
);
212 sigaddset (&sigset
, SIGALRM
);
213 pthread_sigmask (SIG_UNBLOCK
, &sigset
, NULL
);
217 SecDisableInterrupt (
223 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
224 // by enabling/disabling SIGALRM.
225 sigemptyset (&sigset
);
226 sigaddset (&sigset
, SIGALRM
);
227 pthread_sigmask (SIG_BLOCK
, &sigset
, NULL
);
228 gEmulatorInterruptEnabled
= FALSE
;
232 SecInterruptEanbled (
236 return gEmulatorInterruptEnabled
;
240 QueryPerformanceFrequency (
244 // Hard code to nanoseconds
245 return 1000000000ULL;
249 QueryPerformanceCounter (
255 static mach_timebase_info_data_t sTimebaseInfo
;
257 Start
= mach_absolute_time ();
259 // Convert to nanoseconds.
261 // If this is the first time we've run, get the timebase.
262 // We can use denom == 0 to indicate that sTimebaseInfo is
263 // uninitialised because it makes no sense to have a zero
264 // denominator is a fraction.
266 if ( sTimebaseInfo
.denom
== 0 ) {
267 (void)mach_timebase_info (&sTimebaseInfo
);
270 // Do the maths. We hope that the multiplication doesn't
271 // overflow; the price you pay for working in fixed point.
273 return (Start
* sTimebaseInfo
.numer
) / sTimebaseInfo
.denom
;
275 // Need to figure out what to do for Linux?
282 IN UINT64 Nanoseconds
285 struct timespec rq
, rm
;
286 struct timeval start
, end
;
287 unsigned long MicroSec
;
289 rq
.tv_sec
= DivU64x32 (Nanoseconds
, 1000000000);
290 rq
.tv_nsec
= ModU64x32 (Nanoseconds
, 1000000000);
293 // nanosleep gets interrupted by our timer tic.
294 // we need to track wall clock time or we will stall for way too long
296 gettimeofday (&start
, NULL
);
297 end
.tv_sec
= start
.tv_sec
+ rq
.tv_sec
;
298 MicroSec
= (start
.tv_usec
+ rq
.tv_nsec
/1000);
299 end
.tv_usec
= MicroSec
% 1000000;
300 if (MicroSec
> 1000000) {
304 while (nanosleep (&rq
, &rm
) == -1) {
305 if (errno
!= EINTR
) {
309 gettimeofday (&start
, NULL
);
310 if (start
.tv_sec
> end
.tv_sec
) {
314 if ((start
.tv_sec
== end
.tv_sec
) && (start
.tv_usec
> end
.tv_usec
)) {
327 struct timespec rq
, rm
;
329 // nanosleep gets interrupted by the timer tic
333 nanosleep (&rq
, &rm
);
347 OUT EFI_TIME_CAPABILITIES
*Capabilities OPTIONAL
356 Time
->Year
= 1900 + tm
->tm_year
;
357 Time
->Month
= tm
->tm_mon
+ 1;
358 Time
->Day
= tm
->tm_mday
;
359 Time
->Hour
= tm
->tm_hour
;
360 Time
->Minute
= tm
->tm_min
;
361 Time
->Second
= tm
->tm_sec
;
362 Time
->Nanosecond
= 0;
363 Time
->TimeZone
= timezone
/ 60;
364 Time
->Daylight
= (daylight
? EFI_TIME_ADJUST_DAYLIGHT
: 0)
365 | (tm
->tm_isdst
> 0 ? EFI_TIME_IN_DAYLIGHT
: 0);
367 if (Capabilities
!= NULL
) {
368 Capabilities
->Resolution
= 1;
369 Capabilities
->Accuracy
= 50000000;
370 Capabilities
->SetsToZero
= FALSE
;
379 // Don't change the time on the system
380 // We could save delta to localtime() and have SecGetTime adjust return values?
386 IN BOOLEAN EmuBusDriver
,
387 OUT EMU_IO_THUNK_PROTOCOL
**Instance OPTIONAL
390 return GetNextThunkProtocol (EmuBusDriver
, Instance
);
393 EMU_THUNK_PROTOCOL gEmuThunkProtocol
= {
394 GasketSecWriteStdErr
,
395 GasketSecConfigStdIn
,
396 GasketSecWriteStdOut
,
402 GasketSecPeCoffGetEntryPoint
,
403 GasketSecPeCoffRelocateImageExtraAction
,
404 GasketSecPeCoffUnloadImageExtraAction
,
405 GasketSecEnableInterrupt
,
406 GasketSecDisableInterrupt
,
407 GasketQueryPerformanceFrequency
,
408 GasketQueryPerformanceCounter
,
415 GasketSecGetNextProtocol
419 SecInitThunkProtocol (
423 // timezone and daylight lib globals depend on tzset be called 1st.