]> git.proxmox.com Git - mirror_edk2.git/blob - EmulatorPkg/Unix/Host/EmuThunk.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / EmulatorPkg / Unix / Host / EmuThunk.c
1 /*++ @file
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.
5
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.
11
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
15
16 **/
17
18 #include "Host.h"
19
20 #ifdef __APPLE__
21 #define DebugAssert _Mangle__DebugAssert
22
23 #include <assert.h>
24 #include <CoreServices/CoreServices.h>
25 #include <mach/mach.h>
26 #include <mach/mach_time.h>
27
28 #undef DebugAssert
29 #endif
30
31 int settimer_initialized;
32 struct timeval settimer_timeval;
33 UINTN settimer_callback = 0;
34
35 BOOLEAN gEmulatorInterruptEnabled = FALSE;
36
37 UINTN
38 SecWriteStdErr (
39 IN UINT8 *Buffer,
40 IN UINTN NumberOfBytes
41 )
42 {
43 ssize_t Return;
44
45 Return = write (STDERR_FILENO, (const void *)Buffer, (size_t)NumberOfBytes);
46
47 return (Return == -1) ? 0 : Return;
48 }
49
50 EFI_STATUS
51 SecConfigStdIn (
52 VOID
53 )
54 {
55 struct termios tty;
56
57 //
58 // Need to turn off line buffering, ECHO, and make it unbuffered.
59 //
60 tcgetattr (STDIN_FILENO, &tty);
61 tty.c_lflag &= ~(ICANON | ECHO);
62 tcsetattr (STDIN_FILENO, TCSANOW, &tty);
63
64 // setvbuf (STDIN_FILENO, NULL, _IONBF, 0);
65
66 // now ioctl FIONREAD will do what we need
67 return EFI_SUCCESS;
68 }
69
70 UINTN
71 SecWriteStdOut (
72 IN UINT8 *Buffer,
73 IN UINTN NumberOfBytes
74 )
75 {
76 ssize_t Return;
77
78 Return = write (STDOUT_FILENO, (const void *)Buffer, (size_t)NumberOfBytes);
79
80 return (Return == -1) ? 0 : Return;
81 }
82
83 UINTN
84 SecReadStdIn (
85 IN UINT8 *Buffer,
86 IN UINTN NumberOfBytes
87 )
88 {
89 ssize_t Return;
90
91 Return = read (STDIN_FILENO, Buffer, (size_t)NumberOfBytes);
92
93 return (Return == -1) ? 0 : Return;
94 }
95
96 BOOLEAN
97 SecPollStdIn (
98 VOID
99 )
100 {
101 int Result;
102 int Bytes;
103
104 Result = ioctl (STDIN_FILENO, FIONREAD, &Bytes);
105 if (Result == -1) {
106 return FALSE;
107 }
108
109 return (BOOLEAN)(Bytes > 0);
110 }
111
112 VOID *
113 SecMalloc (
114 IN UINTN Size
115 )
116 {
117 return malloc ((size_t)Size);
118 }
119
120 VOID *
121 SecValloc (
122 IN UINTN Size
123 )
124 {
125 return valloc ((size_t)Size);
126 }
127
128 BOOLEAN
129 SecFree (
130 IN VOID *Ptr
131 )
132 {
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.
136 return FALSE;
137 }
138
139 free (Ptr);
140 return TRUE;
141 }
142
143 void
144 settimer_handler (
145 int sig
146 )
147 {
148 struct timeval timeval;
149 UINT64 delta;
150
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;
156
157 if (settimer_callback) {
158 ReverseGasketUint64 (settimer_callback, delta);
159 }
160 }
161
162 VOID
163 SecSetTimer (
164 IN UINT64 PeriodMs,
165 IN EMU_SET_TIMER_CALLBACK CallBack
166 )
167 {
168 struct itimerval timerval;
169 UINT32 remainder;
170
171 if (!settimer_initialized) {
172 struct sigaction act;
173
174 settimer_initialized = 1;
175 act.sa_handler = settimer_handler;
176 act.sa_flags = 0;
177 sigemptyset (&act.sa_mask);
178 gEmulatorInterruptEnabled = TRUE;
179 if (sigaction (SIGALRM, &act, NULL) != 0) {
180 printf ("SetTimer: sigaction error %s\n", strerror (errno));
181 }
182
183 if (gettimeofday (&settimer_timeval, NULL) != 0) {
184 printf ("SetTimer: gettimeofday error %s\n", strerror (errno));
185 }
186 }
187
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;
193
194 if (setitimer (ITIMER_REAL, &timerval, NULL) != 0) {
195 printf ("SetTimer: setitimer error %s\n", strerror (errno));
196 }
197
198 settimer_callback = (UINTN)CallBack;
199 }
200
201 VOID
202 SecEnableInterrupt (
203 VOID
204 )
205 {
206 sigset_t sigset;
207
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);
214 }
215
216 VOID
217 SecDisableInterrupt (
218 VOID
219 )
220 {
221 sigset_t sigset;
222
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;
229 }
230
231 BOOLEAN
232 SecInterruptEanbled (
233 void
234 )
235 {
236 return gEmulatorInterruptEnabled;
237 }
238
239 UINT64
240 QueryPerformanceFrequency (
241 VOID
242 )
243 {
244 // Hard code to nanoseconds
245 return 1000000000ULL;
246 }
247
248 UINT64
249 QueryPerformanceCounter (
250 VOID
251 )
252 {
253 #if __APPLE__
254 UINT64 Start;
255 static mach_timebase_info_data_t sTimebaseInfo;
256
257 Start = mach_absolute_time ();
258
259 // Convert to nanoseconds.
260
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.
265
266 if ( sTimebaseInfo.denom == 0 ) {
267 (void)mach_timebase_info (&sTimebaseInfo);
268 }
269
270 // Do the maths. We hope that the multiplication doesn't
271 // overflow; the price you pay for working in fixed point.
272
273 return (Start * sTimebaseInfo.numer) / sTimebaseInfo.denom;
274 #else
275 // Need to figure out what to do for Linux?
276 return 0;
277 #endif
278 }
279
280 VOID
281 SecSleep (
282 IN UINT64 Nanoseconds
283 )
284 {
285 struct timespec rq, rm;
286 struct timeval start, end;
287 unsigned long MicroSec;
288
289 rq.tv_sec = DivU64x32 (Nanoseconds, 1000000000);
290 rq.tv_nsec = ModU64x32 (Nanoseconds, 1000000000);
291
292 //
293 // nanosleep gets interrupted by our timer tic.
294 // we need to track wall clock time or we will stall for way too long
295 //
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) {
301 end.tv_sec++;
302 }
303
304 while (nanosleep (&rq, &rm) == -1) {
305 if (errno != EINTR) {
306 break;
307 }
308
309 gettimeofday (&start, NULL);
310 if (start.tv_sec > end.tv_sec) {
311 break;
312 }
313
314 if ((start.tv_sec == end.tv_sec) && (start.tv_usec > end.tv_usec)) {
315 break;
316 }
317
318 rq = rm;
319 }
320 }
321
322 VOID
323 SecCpuSleep (
324 VOID
325 )
326 {
327 struct timespec rq, rm;
328
329 // nanosleep gets interrupted by the timer tic
330 rq.tv_sec = 1;
331 rq.tv_nsec = 0;
332
333 nanosleep (&rq, &rm);
334 }
335
336 VOID
337 SecExit (
338 UINTN Status
339 )
340 {
341 exit (Status);
342 }
343
344 VOID
345 SecGetTime (
346 OUT EFI_TIME *Time,
347 OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
348 )
349 {
350 struct tm *tm;
351 time_t t;
352
353 t = time (NULL);
354 tm = localtime (&t);
355
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);
366
367 if (Capabilities != NULL) {
368 Capabilities->Resolution = 1;
369 Capabilities->Accuracy = 50000000;
370 Capabilities->SetsToZero = FALSE;
371 }
372 }
373
374 VOID
375 SecSetTime (
376 IN EFI_TIME *Time
377 )
378 {
379 // Don't change the time on the system
380 // We could save delta to localtime() and have SecGetTime adjust return values?
381 return;
382 }
383
384 EFI_STATUS
385 SecGetNextProtocol (
386 IN BOOLEAN EmuBusDriver,
387 OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL
388 )
389 {
390 return GetNextThunkProtocol (EmuBusDriver, Instance);
391 }
392
393 EMU_THUNK_PROTOCOL gEmuThunkProtocol = {
394 GasketSecWriteStdErr,
395 GasketSecConfigStdIn,
396 GasketSecWriteStdOut,
397 GasketSecReadStdIn,
398 GasketSecPollStdIn,
399 GasketSecMalloc,
400 GasketSecValloc,
401 GasketSecFree,
402 GasketSecPeCoffGetEntryPoint,
403 GasketSecPeCoffRelocateImageExtraAction,
404 GasketSecPeCoffUnloadImageExtraAction,
405 GasketSecEnableInterrupt,
406 GasketSecDisableInterrupt,
407 GasketQueryPerformanceFrequency,
408 GasketQueryPerformanceCounter,
409 GasketSecSleep,
410 GasketSecCpuSleep,
411 GasketSecExit,
412 GasketSecGetTime,
413 GasketSecSetTime,
414 GasketSecSetTimer,
415 GasketSecGetNextProtocol
416 };
417
418 VOID
419 SecInitThunkProtocol (
420 VOID
421 )
422 {
423 // timezone and daylight lib globals depend on tzset be called 1st.
424 tzset ();
425 }