]>
Commit | Line | Data |
---|---|---|
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 | ||
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 | |
18 | ||
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. | |
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 | ||
37 | int settimer_initialized; | |
38 | struct timeval settimer_timeval; | |
39 | void (*settimer_callback)(UINT64 delta); | |
40 | ||
41 | BOOLEAN gEmulatorInterruptEnabled = FALSE; | |
42 | ||
43 | ||
44 | UINTN | |
45 | SecWriteStdErr ( | |
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 | 58 | EFI_STATUS |
59 | SecConfigStdIn ( | |
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 | ||
78 | UINTN | |
79 | SecWriteStdOut ( | |
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 | ||
91 | UINTN | |
92 | SecReadStdIn ( | |
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 | ||
104 | BOOLEAN | |
105 | SecPollStdIn ( | |
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 | ||
949f388f | 121 | |
122 | void | |
123 | settimer_handler (int sig) | |
124 | { | |
125 | struct timeval timeval; | |
126 | UINT64 delta; | |
127 | ||
128 | gettimeofday (&timeval, NULL); | |
129 | delta = ((UINT64)timeval.tv_sec * 1000) + (timeval.tv_usec / 1000) | |
130 | - ((UINT64)settimer_timeval.tv_sec * 1000) | |
131 | - (settimer_timeval.tv_usec / 1000); | |
132 | settimer_timeval = timeval; | |
133 | ||
134 | if (settimer_callback) { | |
135 | ReverseGasketUint64 (settimer_callback, delta); | |
136 | } | |
137 | } | |
138 | ||
139 | VOID | |
140 | SecSetTimer ( | |
141 | IN UINT64 PeriodMs, | |
142 | IN EMU_SET_TIMER_CALLBACK CallBack | |
143 | ) | |
144 | { | |
145 | struct itimerval timerval; | |
146 | UINT32 remainder; | |
147 | ||
148 | if (!settimer_initialized) { | |
149 | struct sigaction act; | |
150 | ||
151 | settimer_initialized = 1; | |
152 | act.sa_handler = settimer_handler; | |
153 | act.sa_flags = 0; | |
154 | sigemptyset (&act.sa_mask); | |
155 | gEmulatorInterruptEnabled = TRUE; | |
156 | if (sigaction (SIGALRM, &act, NULL) != 0) { | |
157 | printf ("SetTimer: sigaction error %s\n", strerror (errno)); | |
158 | } | |
159 | if (gettimeofday (&settimer_timeval, NULL) != 0) { | |
160 | printf ("SetTimer: gettimeofday error %s\n", strerror (errno)); | |
161 | } | |
162 | } | |
163 | timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000); | |
164 | DivU64x32Remainder(PeriodMs, 1000, &remainder); | |
165 | timerval.it_value.tv_usec = remainder * 1000; | |
166 | timerval.it_value.tv_sec = DivU64x32(PeriodMs, 1000); | |
167 | timerval.it_interval = timerval.it_value; | |
168 | ||
169 | if (setitimer (ITIMER_REAL, &timerval, NULL) != 0) { | |
170 | printf ("SetTimer: setitimer error %s\n", strerror (errno)); | |
171 | } | |
172 | settimer_callback = CallBack; | |
173 | } | |
174 | ||
175 | ||
176 | VOID | |
177 | SecEnableInterrupt ( | |
178 | VOID | |
179 | ) | |
180 | { | |
181 | sigset_t sigset; | |
182 | ||
183 | gEmulatorInterruptEnabled = TRUE; | |
184 | // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts | |
185 | // by enabling/disabling SIGALRM. | |
186 | sigemptyset (&sigset); | |
187 | sigaddset (&sigset, SIGALRM); | |
188 | pthread_sigmask (SIG_UNBLOCK, &sigset, NULL); | |
189 | } | |
190 | ||
191 | ||
192 | VOID | |
193 | SecDisableInterrupt ( | |
194 | VOID | |
195 | ) | |
196 | { | |
197 | sigset_t sigset; | |
198 | ||
199 | // Since SetTimer() uses SIGALRM we emulate turning on and off interrupts | |
200 | // by enabling/disabling SIGALRM. | |
201 | sigemptyset (&sigset); | |
202 | sigaddset (&sigset, SIGALRM); | |
203 | pthread_sigmask (SIG_BLOCK, &sigset, NULL); | |
204 | gEmulatorInterruptEnabled = FALSE; | |
205 | } | |
206 | ||
207 | ||
208 | BOOLEAN | |
209 | SecInterruptEanbled (void) | |
210 | { | |
211 | return gEmulatorInterruptEnabled; | |
212 | } | |
213 | ||
214 | ||
215 | UINT64 | |
216 | QueryPerformanceFrequency ( | |
217 | VOID | |
218 | ) | |
219 | { | |
220 | // Hard code to nanoseconds | |
221 | return 1000000000ULL; | |
222 | } | |
223 | ||
224 | UINT64 | |
225 | QueryPerformanceCounter ( | |
226 | VOID | |
227 | ) | |
228 | { | |
229 | #if __APPLE__ | |
230 | UINT64 Start; | |
231 | Nanoseconds elapsedNano; | |
232 | ||
233 | Start = mach_absolute_time (); | |
234 | ||
235 | // Convert to nanoseconds. | |
236 | ||
237 | // Have to do some pointer fun because AbsoluteToNanoseconds | |
238 | // works in terms of UnsignedWide, which is a structure rather | |
239 | // than a proper 64-bit integer. | |
240 | elapsedNano = AbsoluteToNanoseconds (*(AbsoluteTime *) &Start); | |
241 | ||
242 | return *(uint64_t *) &elapsedNano; | |
243 | #else | |
244 | // Need to figure out what to do for Linux? | |
245 | return 0; | |
246 | #endif | |
247 | } | |
248 | ||
249 | ||
250 | ||
251 | VOID | |
252 | SecSleep ( | |
253 | IN UINT64 Milliseconds | |
254 | ) | |
255 | { | |
256 | struct timespec rq, rm; | |
257 | struct timeval start, end; | |
258 | unsigned long MicroSec; | |
259 | ||
260 | rq.tv_sec = Milliseconds / 1000; | |
261 | rq.tv_nsec = (Milliseconds % 1000) * 1000000; | |
262 | ||
263 | // | |
264 | // nanosleep gets interrupted by our timer tic. | |
265 | // we need to track wall clock time or we will stall for way too long | |
266 | // | |
267 | gettimeofday (&start, NULL); | |
268 | end.tv_sec = start.tv_sec + rq.tv_sec; | |
269 | MicroSec = (start.tv_usec + rq.tv_nsec/1000); | |
270 | end.tv_usec = MicroSec % 1000000; | |
271 | if (MicroSec > 1000000) { | |
272 | end.tv_sec++; | |
273 | } | |
274 | ||
275 | while (nanosleep (&rq, &rm) == -1) { | |
276 | if (errno != EINTR) { | |
277 | break; | |
278 | } | |
279 | gettimeofday (&start, NULL); | |
280 | if (start.tv_sec > end.tv_sec) { | |
281 | break; | |
282 | } if ((start.tv_sec == end.tv_sec) && (start.tv_usec > end.tv_usec)) { | |
283 | break; | |
284 | } | |
285 | rq = rm; | |
286 | } | |
287 | } | |
288 | ||
289 | VOID | |
290 | SecExit ( | |
291 | UINTN Status | |
292 | ) | |
293 | { | |
294 | exit (Status); | |
295 | } | |
296 | ||
297 | ||
298 | VOID | |
299 | SecGetTime ( | |
300 | OUT EFI_TIME *Time, | |
301 | OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL | |
302 | ) | |
303 | { | |
304 | struct tm *tm; | |
305 | time_t t; | |
306 | ||
307 | t = time (NULL); | |
308 | tm = localtime (&t); | |
309 | ||
310 | Time->Year = 1900 + tm->tm_year; | |
311 | Time->Month = tm->tm_mon + 1; | |
312 | Time->Day = tm->tm_mday; | |
313 | Time->Hour = tm->tm_hour; | |
314 | Time->Minute = tm->tm_min; | |
315 | Time->Second = tm->tm_sec; | |
316 | Time->Nanosecond = 0; | |
317 | Time->TimeZone = timezone; | |
318 | Time->Daylight = (daylight ? EFI_TIME_ADJUST_DAYLIGHT : 0) | |
319 | | (tm->tm_isdst > 0 ? EFI_TIME_IN_DAYLIGHT : 0); | |
320 | ||
321 | if (Capabilities != NULL) { | |
322 | Capabilities->Resolution = 1; | |
323 | Capabilities->Accuracy = 50000000; | |
324 | Capabilities->SetsToZero = FALSE; | |
325 | } | |
326 | } | |
327 | ||
328 | ||
329 | ||
330 | VOID | |
331 | SecSetTime ( | |
332 | IN EFI_TIME *Time | |
333 | ) | |
334 | { | |
335 | // Don't change the time on the system | |
336 | // We could save delta to localtime() and have SecGetTime adjust return values? | |
337 | return; | |
338 | } | |
339 | ||
340 | ||
341 | EFI_STATUS | |
342 | SecGetNextProtocol ( | |
343 | IN BOOLEAN EmuBusDriver, | |
344 | OUT EMU_IO_THUNK_PROTOCOL **Instance OPTIONAL | |
345 | ) | |
346 | { | |
347 | return GetNextThunkProtocol (EmuBusDriver, Instance); | |
348 | } | |
349 | ||
350 | ||
351 | EMU_THUNK_PROTOCOL gEmuThunkProtocol = { | |
352 | GasketSecWriteStdErr, | |
7e284acb | 353 | GasketSecConfigStdIn, |
354 | GasketSecWriteStdOut, | |
355 | GasketSecReadStdIn, | |
356 | GasketSecPollStdIn, | |
949f388f | 357 | GasketSecPeCoffGetEntryPoint, |
358 | GasketSecPeCoffRelocateImageExtraAction, | |
359 | GasketSecPeCoffUnloadImageExtraAction, | |
360 | GasketSecEnableInterrupt, | |
361 | GasketSecDisableInterrupt, | |
362 | GasketQueryPerformanceFrequency, | |
363 | GasketQueryPerformanceCounter, | |
364 | GasketSecSleep, | |
365 | GasketSecExit, | |
366 | GasketSecGetTime, | |
367 | GasketSecSetTime, | |
368 | GasketSecSetTimer, | |
369 | GasketSecGetNextProtocol | |
370 | }; | |
371 | ||
372 | ||
373 | VOID | |
374 | SecInitThunkProtocol ( | |
375 | VOID | |
376 | ) | |
377 | { | |
378 | // timezone and daylight lib globals depend on tzset be called 1st. | |
379 | tzset (); | |
380 | } | |
381 |