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 - 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
;
41 IN UINTN NumberOfBytes
46 Return
= write (STDERR_FILENO
, (const void *)Buffer
, (size_t)NumberOfBytes
);
48 return (Return
== -1) ? 0 : Return
;
60 // Need to turn off line buffering, ECHO, and make it unbuffered.
62 tcgetattr (STDIN_FILENO
, &tty
);
63 tty
.c_lflag
&= ~(ICANON
| ECHO
);
64 tcsetattr (STDIN_FILENO
, TCSANOW
, &tty
);
66 // setvbuf (STDIN_FILENO, NULL, _IONBF, 0);
68 // now ioctl FIONREAD will do what we need
75 IN UINTN NumberOfBytes
80 Return
= write (STDOUT_FILENO
, (const void *)Buffer
, (size_t)NumberOfBytes
);
82 return (Return
== -1) ? 0 : Return
;
88 IN UINTN NumberOfBytes
93 Return
= read (STDIN_FILENO
, Buffer
, (size_t)NumberOfBytes
);
95 return (Return
== -1) ? 0 : Return
;
106 Result
= ioctl (STDIN_FILENO
, FIONREAD
, &Bytes
);
111 return (BOOLEAN
)(Bytes
> 0);
120 return malloc ((size_t)Size
);
128 return valloc ((size_t)Size
);
136 if (EfiSystemMemoryRange (Ptr
)) {
137 // If an address range is in the EFI memory map it was alloced via EFI.
138 // So don't free those ranges and let the caller know.
148 settimer_handler (int sig
)
150 struct timeval timeval
;
153 gettimeofday (&timeval
, NULL
);
154 delta
= ((UINT64
)timeval
.tv_sec
* 1000) + (timeval
.tv_usec
/ 1000)
155 - ((UINT64
)settimer_timeval
.tv_sec
* 1000)
156 - (settimer_timeval
.tv_usec
/ 1000);
157 settimer_timeval
= timeval
;
159 if (settimer_callback
) {
160 ReverseGasketUint64 (settimer_callback
, delta
);
167 IN EMU_SET_TIMER_CALLBACK CallBack
170 struct itimerval timerval
;
173 if (!settimer_initialized
) {
174 struct sigaction act
;
176 settimer_initialized
= 1;
177 act
.sa_handler
= settimer_handler
;
179 sigemptyset (&act
.sa_mask
);
180 gEmulatorInterruptEnabled
= TRUE
;
181 if (sigaction (SIGALRM
, &act
, NULL
) != 0) {
182 printf ("SetTimer: sigaction error %s\n", strerror (errno
));
184 if (gettimeofday (&settimer_timeval
, NULL
) != 0) {
185 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
));
197 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
);
218 SecDisableInterrupt (
224 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
225 // by enabling/disabling SIGALRM.
226 sigemptyset (&sigset
);
227 sigaddset (&sigset
, SIGALRM
);
228 pthread_sigmask (SIG_BLOCK
, &sigset
, NULL
);
229 gEmulatorInterruptEnabled
= FALSE
;
234 SecInterruptEanbled (void)
236 return gEmulatorInterruptEnabled
;
241 QueryPerformanceFrequency (
245 // Hard code to nanoseconds
246 return 1000000000ULL;
250 QueryPerformanceCounter (
256 static mach_timebase_info_data_t sTimebaseInfo
;
259 Start
= mach_absolute_time ();
261 // Convert to nanoseconds.
263 // If this is the first time we've run, get the timebase.
264 // We can use denom == 0 to indicate that sTimebaseInfo is
265 // uninitialised because it makes no sense to have a zero
266 // denominator is a fraction.
268 if ( sTimebaseInfo
.denom
== 0 ) {
269 (void) mach_timebase_info(&sTimebaseInfo
);
272 // Do the maths. We hope that the multiplication doesn't
273 // overflow; the price you pay for working in fixed point.
275 return (Start
* sTimebaseInfo
.numer
) / sTimebaseInfo
.denom
;
277 // Need to figure out what to do for Linux?
286 IN UINT64 Nanoseconds
289 struct timespec rq
, rm
;
290 struct timeval start
, end
;
291 unsigned long MicroSec
;
293 rq
.tv_sec
= DivU64x32 (Nanoseconds
, 1000000000);
294 rq
.tv_nsec
= ModU64x32 (Nanoseconds
, 1000000000);
297 // nanosleep gets interrupted by our timer tic.
298 // we need to track wall clock time or we will stall for way too long
300 gettimeofday (&start
, NULL
);
301 end
.tv_sec
= start
.tv_sec
+ rq
.tv_sec
;
302 MicroSec
= (start
.tv_usec
+ rq
.tv_nsec
/1000);
303 end
.tv_usec
= MicroSec
% 1000000;
304 if (MicroSec
> 1000000) {
308 while (nanosleep (&rq
, &rm
) == -1) {
309 if (errno
!= EINTR
) {
312 gettimeofday (&start
, NULL
);
313 if (start
.tv_sec
> end
.tv_sec
) {
315 } if ((start
.tv_sec
== end
.tv_sec
) && (start
.tv_usec
> end
.tv_usec
)) {
328 struct timespec rq
, rm
;
330 // nanosleep gets interrupted by the timer tic
334 nanosleep (&rq
, &rm
);
350 OUT EFI_TIME_CAPABILITIES
*Capabilities OPTIONAL
359 Time
->Year
= 1900 + tm
->tm_year
;
360 Time
->Month
= tm
->tm_mon
+ 1;
361 Time
->Day
= tm
->tm_mday
;
362 Time
->Hour
= tm
->tm_hour
;
363 Time
->Minute
= tm
->tm_min
;
364 Time
->Second
= tm
->tm_sec
;
365 Time
->Nanosecond
= 0;
366 Time
->TimeZone
= timezone
/ 60;
367 Time
->Daylight
= (daylight
? EFI_TIME_ADJUST_DAYLIGHT
: 0)
368 | (tm
->tm_isdst
> 0 ? EFI_TIME_IN_DAYLIGHT
: 0);
370 if (Capabilities
!= NULL
) {
371 Capabilities
->Resolution
= 1;
372 Capabilities
->Accuracy
= 50000000;
373 Capabilities
->SetsToZero
= FALSE
;
384 // Don't change the time on the system
385 // We could save delta to localtime() and have SecGetTime adjust return values?
392 IN BOOLEAN EmuBusDriver
,
393 OUT EMU_IO_THUNK_PROTOCOL
**Instance OPTIONAL
396 return GetNextThunkProtocol (EmuBusDriver
, Instance
);
400 EMU_THUNK_PROTOCOL gEmuThunkProtocol
= {
401 GasketSecWriteStdErr
,
402 GasketSecConfigStdIn
,
403 GasketSecWriteStdOut
,
409 GasketSecPeCoffGetEntryPoint
,
410 GasketSecPeCoffRelocateImageExtraAction
,
411 GasketSecPeCoffUnloadImageExtraAction
,
412 GasketSecEnableInterrupt
,
413 GasketSecDisableInterrupt
,
414 GasketQueryPerformanceFrequency
,
415 GasketQueryPerformanceCounter
,
422 GasketSecGetNextProtocol
427 SecInitThunkProtocol (
431 // timezone and daylight lib globals depend on tzset be called 1st.