]> git.proxmox.com Git - mirror_edk2.git/blame - InOsEmuPkg/Unix/Sec/EmuThunk.c
Clarify the requirements for the Destination parameter of UnicodeStrToAsciiStr.
[mirror_edk2.git] / InOsEmuPkg / Unix / Sec / EmuThunk.c
CommitLineData
949f388f 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 initaliized with the members at the end being
10 set to zero. This is bad as jumping to zero will crash.
11
12Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
13Portions copyright (c) 2008 - 2011, Apple Inc. All rights reserved.<BR>
14This program and the accompanying materials
15are licensed and made available under the terms and conditions of the BSD License
16which accompanies this distribution. The full text of the license may be found at
17http://opensource.org/licenses/bsd-license.php
18
19THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
20WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
21
22**/
23
24#include "SecMain.h"
25
26#ifdef __APPLE__
27#define DebugAssert _Mangle__DebugAssert
28
29#include <assert.h>
30#include <CoreServices/CoreServices.h>
31#include <mach/mach.h>
32#include <mach/mach_time.h>
33
34#undef DebugAssert
35#endif
36
37int settimer_initialized;
38struct timeval settimer_timeval;
39void (*settimer_callback)(UINT64 delta);
40
41BOOLEAN gEmulatorInterruptEnabled = FALSE;
42
43
44UINTN
45SecWriteStdErr (
46 IN UINT8 *Buffer,
47 IN UINTN NumberOfBytes
48 )
49{
50 ssize_t Return;
51
7e284acb 52 Return = write (STDERR_FILENO, (const void *)Buffer, (size_t)NumberOfBytes);
949f388f 53
54 return (Return == -1) ? 0 : Return;
55}
56
57
7e284acb 58EFI_STATUS
59SecConfigStdIn (
60 VOID
61 )
62{
63 struct termios tty;
64
65 //
66 // Need to turn off line buffering, ECHO, and make it unbuffered.
67 //
68 tcgetattr (STDIN_FILENO, &tty);
69 tty.c_lflag &= ~(ICANON | ECHO);
70 tcsetattr (STDIN_FILENO, TCSANOW, &tty);
71
72// setvbuf (STDIN_FILENO, NULL, _IONBF, 0);
73
74 // now ioctl FIONREAD will do what we need
75 return EFI_SUCCESS;
76}
77
78UINTN
79SecWriteStdOut (
80 IN UINT8 *Buffer,
81 IN UINTN NumberOfBytes
82 )
83{
84 ssize_t Return;
85
86 Return = write (STDOUT_FILENO, (const void *)Buffer, (size_t)NumberOfBytes);
87
88 return (Return == -1) ? 0 : Return;
89}
90
91UINTN
92SecReadStdIn (
93 IN UINT8 *Buffer,
94 IN UINTN NumberOfBytes
95 )
96{
97 ssize_t Return;
98
99 Return = read (STDIN_FILENO, Buffer, (size_t)NumberOfBytes);
100
101 return (Return == -1) ? 0 : Return;
102}
103
104BOOLEAN
105SecPollStdIn (
106 VOID
107 )
108{
109 int Result;
110 int Bytes;
111
112 Result = ioctl (STDIN_FILENO, FIONREAD, &Bytes);
113 if (Result == -1) {
114 return FALSE;
115 }
116
117 return (BOOLEAN)(Bytes > 0);
118}
119
120
c2175068 121VOID *
122SecMalloc (
123 IN UINTN Size
124 )
125{
126 return malloc ((size_t)Size);
127}
128
1d7ac5a6 129VOID *
130SecValloc (
131 IN UINTN Size
132 )
133{
134 return valloc ((size_t)Size);
135}
136
137BOOLEAN
c2175068 138SecFree (
139 IN VOID *Ptr
140 )
141{
1d7ac5a6 142 if (EfiSystemMemoryRange (Ptr)) {
143 // If an address range is in the EFI memory map it was alloced via EFI.
144 // So don't free those ranges and let the caller know.
145 return FALSE;
146 }
147
c2175068 148 free (Ptr);
1d7ac5a6 149 return TRUE;
c2175068 150}
151
949f388f 152
153void
154settimer_handler (int sig)
155{
156 struct timeval timeval;
157 UINT64 delta;
158
159 gettimeofday (&timeval, NULL);
160 delta = ((UINT64)timeval.tv_sec * 1000) + (timeval.tv_usec / 1000)
161 - ((UINT64)settimer_timeval.tv_sec * 1000)
162 - (settimer_timeval.tv_usec / 1000);
163 settimer_timeval = timeval;
164
165 if (settimer_callback) {
166 ReverseGasketUint64 (settimer_callback, delta);
167 }
168}
169
170VOID
171SecSetTimer (
172 IN UINT64 PeriodMs,
173 IN EMU_SET_TIMER_CALLBACK CallBack
174 )
175{
176 struct itimerval timerval;
177 UINT32 remainder;
178
179 if (!settimer_initialized) {
180 struct sigaction act;
181
182 settimer_initialized = 1;
183 act.sa_handler = settimer_handler;
184 act.sa_flags = 0;
185 sigemptyset (&act.sa_mask);
186 gEmulatorInterruptEnabled = TRUE;
187 if (sigaction (SIGALRM, &act, NULL) != 0) {
188 printf ("SetTimer: sigaction error %s\n", strerror (errno));
189 }
190 if (gettimeofday (&settimer_timeval, NULL) != 0) {
191 printf ("SetTimer: gettimeofday error %s\n", strerror (errno));
192 }
193 }
194 timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000);
195 DivU64x32Remainder(PeriodMs, 1000, &remainder);
196 timerval.it_value.tv_usec = remainder * 1000;
197 timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000);
198 timerval.it_interval = timerval.it_value;
199
200 if (setitimer (ITIMER_REAL, &timerval, NULL) != 0) {
201 printf ("SetTimer: setitimer error %s\n", strerror (errno));
202 }
203 settimer_callback = CallBack;
204}
205
206
207VOID
208SecEnableInterrupt (
209 VOID
210 )
211{
212 sigset_t sigset;
213
214 gEmulatorInterruptEnabled = TRUE;
215 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
216 // by enabling/disabling SIGALRM.
217 sigemptyset (&sigset);
218 sigaddset (&sigset, SIGALRM);
219 pthread_sigmask (SIG_UNBLOCK, &sigset, NULL);
220}
221
222
223VOID
224SecDisableInterrupt (
225 VOID
226 )
227{
228 sigset_t sigset;
229
230 // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts
231 // by enabling/disabling SIGALRM.
232 sigemptyset (&sigset);
233 sigaddset (&sigset, SIGALRM);
234 pthread_sigmask (SIG_BLOCK, &sigset, NULL);
235 gEmulatorInterruptEnabled = FALSE;
236}
237
238
239BOOLEAN
240SecInterruptEanbled (void)
241{
242 return gEmulatorInterruptEnabled;
243}
244
245
246UINT64
247QueryPerformanceFrequency (
248 VOID
249 )
250{
251 // Hard code to nanoseconds
252 return 1000000000ULL;
253}
254
255UINT64
256QueryPerformanceCounter (
257 VOID
258 )
259{
260#if __APPLE__
261 UINT64 Start;
262 Nanoseconds elapsedNano;
263
264 Start = mach_absolute_time ();
265
266 // Convert to nanoseconds.
267
268 // Have to do some pointer fun because AbsoluteToNanoseconds
269 // works in terms of UnsignedWide, which is a structure rather
270 // than a proper 64-bit integer.
271 elapsedNano = AbsoluteToNanoseconds (*(AbsoluteTime *) &Start);
272
273 return *(uint64_t *) &elapsedNano;
274#else
275 // Need to figure out what to do for Linux?
276 return 0;
277#endif
278}
279
280
281
282VOID
283SecSleep (
1ef41207 284 IN UINT64 Nanoseconds
949f388f 285 )
286{
287 struct timespec rq, rm;
288 struct timeval start, end;
289 unsigned long MicroSec;
290
54e0b04c 291 rq.tv_sec = DivU64x32 (Nanoseconds, 1000000000);
292 rq.tv_nsec = ModU64x32 (Nanoseconds, 1000000000);
949f388f 293
294 //
295 // nanosleep gets interrupted by our timer tic.
296 // we need to track wall clock time or we will stall for way too long
297 //
298 gettimeofday (&start, NULL);
299 end.tv_sec = start.tv_sec + rq.tv_sec;
300 MicroSec = (start.tv_usec + rq.tv_nsec/1000);
301 end.tv_usec = MicroSec % 1000000;
302 if (MicroSec > 1000000) {
303 end.tv_sec++;
304 }
305
306 while (nanosleep (&rq, &rm) == -1) {
307 if (errno != EINTR) {
308 break;
309 }
310 gettimeofday (&start, NULL);
311 if (start.tv_sec > end.tv_sec) {
312 break;
313 } if ((start.tv_sec == end.tv_sec) && (start.tv_usec > end.tv_usec)) {
314 break;
315 }
316 rq = rm;
317 }
318}
319
57c7d70f 320
321VOID
322SecCpuSleep (
323 VOID
324 )
325{
326 struct timespec rq, rm;
327
328 // nanosleep gets interrupted by the timer tic
329 rq.tv_sec = 1;
330 rq.tv_nsec = 0;
331
332 nanosleep (&rq, &rm);
333}
334
335
949f388f 336VOID
337SecExit (
338 UINTN Status
339 )
340{
341 exit (Status);
342}
343
344
345VOID
346SecGetTime (
347 OUT EFI_TIME *Time,
348 OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
349 )
350{
351 struct tm *tm;
352 time_t t;
353
354 t = time (NULL);
355 tm = localtime (&t);
356
357 Time->Year = 1900 + tm->tm_year;
358 Time->Month = tm->tm_mon + 1;
359 Time->Day = tm->tm_mday;
360 Time->Hour = tm->tm_hour;
361 Time->Minute = tm->tm_min;
362 Time->Second = tm->tm_sec;
363 Time->Nanosecond = 0;
364 Time->TimeZone = timezone;
365 Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0)
366 | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0);
367
368 if (Capabilities != NULL) {
369 Capabilities->Resolution = 1;
370 Capabilities->Accuracy = 50000000;
371 Capabilities->SetsToZero = FALSE;
372 }
373}
374
375
376
377VOID
378SecSetTime (
379 IN EFI_TIME *Time
380 )
381{
382 // Don't change the time on the system
383 // We could save delta to localtime() and have SecGetTime adjust return values?
384 return;
385}
386
387
388EFI_STATUS
389SecGetNextProtocol (
390 IN BOOLEAN EmuBusDriver,
391 OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL
392 )
393{
394 return GetNextThunkProtocol (EmuBusDriver, Instance);
395}
396
397
398EMU_THUNK_PROTOCOL gEmuThunkProtocol = {
399 GasketSecWriteStdErr,
7e284acb 400 GasketSecConfigStdIn,
401 GasketSecWriteStdOut,
402 GasketSecReadStdIn,
403 GasketSecPollStdIn,
c2175068 404 GasketSecMalloc,
1d7ac5a6 405 GasketSecValloc,
c2175068 406 GasketSecFree,
949f388f 407 GasketSecPeCoffGetEntryPoint,
408 GasketSecPeCoffRelocateImageExtraAction,
409 GasketSecPeCoffUnloadImageExtraAction,
410 GasketSecEnableInterrupt,
411 GasketSecDisableInterrupt,
412 GasketQueryPerformanceFrequency,
413 GasketQueryPerformanceCounter,
414 GasketSecSleep,
57c7d70f 415 GasketSecCpuSleep,
949f388f 416 GasketSecExit,
417 GasketSecGetTime,
418 GasketSecSetTime,
419 GasketSecSetTimer,
420 GasketSecGetNextProtocol
421};
422
423
424VOID
425SecInitThunkProtocol (
426 VOID
427 )
428{
429 // timezone and daylight lib globals depend on tzset be called 1st.
430 tzset ();
431}
432