]>
Commit | Line | Data |
---|---|---|
3c859dfe RN |
1 | /**@file\r |
2 | \r | |
3 | Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r | |
e3ba31da | 4 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
3c859dfe RN |
5 | \r |
6 | Module Name:\r | |
7 | \r | |
8 | WinNtThunk.c\r | |
9 | \r | |
10 | Abstract:\r | |
11 | \r | |
12 | Since the SEC is the only windows program in our emulation we\r | |
13 | must use a Tiano mechanism to export Win32 APIs to other modules.\r | |
14 | This is the role of the EFI_WIN_NT_THUNK_PROTOCOL.\r | |
15 | \r | |
16 | The mWinNtThunkTable exists so that a change to EFI_WIN_NT_THUNK_PROTOCOL\r | |
17 | will cause an error in initializing the array if all the member functions\r | |
18 | are not added. It looks like adding a element to end and not initializing\r | |
19 | it may cause the table to be initaliized with the members at the end being\r | |
20 | set to zero. This is bad as jumping to zero will case the NT32 to crash.\r | |
21 | \r | |
22 | All the member functions in mWinNtThunkTable are Win32\r | |
23 | API calls, so please reference Microsoft documentation.\r | |
24 | \r | |
25 | \r | |
26 | gWinNt is a a public exported global that contains the initialized\r | |
27 | data.\r | |
28 | \r | |
29 | **/\r | |
30 | \r | |
31 | #include "WinHost.h"\r | |
32 | \r | |
33 | UINTN\r | |
34 | SecWriteStdErr (\r | |
35 | IN UINT8 *Buffer,\r | |
36 | IN UINTN NumberOfBytes\r | |
37 | )\r | |
38 | {\r | |
5601e90d RN |
39 | BOOL Success;\r |
40 | DWORD CharCount;\r | |
41 | \r | |
42 | CharCount = (DWORD)NumberOfBytes;\r | |
43 | Success = WriteFile (\r | |
44 | GetStdHandle (STD_ERROR_HANDLE),\r | |
45 | Buffer,\r | |
46 | CharCount,\r | |
47 | &CharCount,\r | |
48 | NULL\r | |
49 | );\r | |
50 | \r | |
51 | return Success ? CharCount : 0;\r | |
3c859dfe RN |
52 | }\r |
53 | \r | |
54 | \r | |
55 | EFI_STATUS\r | |
56 | SecConfigStdIn (\r | |
57 | VOID\r | |
58 | )\r | |
59 | {\r | |
5601e90d RN |
60 | BOOL Success;\r |
61 | DWORD Mode;\r | |
62 | \r | |
63 | Success = GetConsoleMode (GetStdHandle (STD_INPUT_HANDLE), &Mode);\r | |
64 | if (Success) {\r | |
65 | //\r | |
66 | // Disable buffer (line input), echo, mouse, window\r | |
67 | //\r | |
f4eaaf1a RN |
68 | Mode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);\r |
69 | \r | |
70 | #if defined(NTDDI_VERSION) && defined (NTDDI_WIN10_TH2) && (NTDDI_VERSION > NTDDI_WIN10_TH2)\r | |
5601e90d | 71 | //\r |
f4eaaf1a | 72 | // Enable virtual terminal input for Win10 above TH2\r |
5601e90d | 73 | //\r |
f4eaaf1a RN |
74 | Mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;\r |
75 | #endif\r | |
76 | \r | |
77 | Success = SetConsoleMode (GetStdHandle (STD_INPUT_HANDLE), Mode);\r | |
78 | }\r | |
79 | \r | |
80 | #if defined(NTDDI_VERSION) && defined (NTDDI_WIN10_TH2) && (NTDDI_VERSION > NTDDI_WIN10_TH2)\r | |
81 | //\r | |
82 | // Enable terminal mode for Win10 above TH2\r | |
83 | //\r | |
84 | if (Success) {\r | |
5601e90d RN |
85 | Success = GetConsoleMode (GetStdHandle (STD_OUTPUT_HANDLE), &Mode);\r |
86 | if (Success) {\r | |
87 | Success = SetConsoleMode (\r | |
88 | GetStdHandle (STD_OUTPUT_HANDLE),\r | |
89 | Mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN\r | |
90 | );\r | |
91 | }\r | |
92 | }\r | |
f4eaaf1a | 93 | #endif\r |
5601e90d | 94 | return Success ? EFI_SUCCESS : EFI_DEVICE_ERROR;\r |
3c859dfe RN |
95 | }\r |
96 | \r | |
97 | UINTN\r | |
98 | SecWriteStdOut (\r | |
99 | IN UINT8 *Buffer,\r | |
100 | IN UINTN NumberOfBytes\r | |
101 | )\r | |
102 | {\r | |
5601e90d RN |
103 | BOOL Success;\r |
104 | DWORD CharCount;\r | |
105 | \r | |
106 | CharCount = (DWORD)NumberOfBytes;\r | |
107 | Success = WriteFile (\r | |
108 | GetStdHandle (STD_OUTPUT_HANDLE),\r | |
109 | Buffer,\r | |
110 | CharCount,\r | |
111 | &CharCount,\r | |
112 | NULL\r | |
113 | );\r | |
114 | \r | |
115 | return Success ? CharCount : 0;\r | |
3c859dfe RN |
116 | }\r |
117 | \r | |
118 | BOOLEAN\r | |
119 | SecPollStdIn (\r | |
120 | VOID\r | |
121 | )\r | |
122 | {\r | |
5601e90d RN |
123 | BOOL Success;\r |
124 | INPUT_RECORD Record;\r | |
125 | DWORD RecordNum;\r | |
126 | \r | |
127 | do {\r | |
128 | Success = GetNumberOfConsoleInputEvents (GetStdHandle (STD_INPUT_HANDLE), &RecordNum);\r | |
129 | if (!Success || (RecordNum == 0)) {\r | |
130 | break;\r | |
131 | }\r | |
132 | Success = PeekConsoleInput (\r | |
133 | GetStdHandle (STD_INPUT_HANDLE),\r | |
134 | &Record,\r | |
135 | 1,\r | |
136 | &RecordNum\r | |
137 | );\r | |
138 | if (Success && (RecordNum == 1)) {\r | |
139 | if (Record.EventType == KEY_EVENT && Record.Event.KeyEvent.bKeyDown) {\r | |
140 | return TRUE;\r | |
141 | } else {\r | |
142 | //\r | |
143 | // Consume the non-key event.\r | |
144 | //\r | |
145 | Success = ReadConsoleInput (\r | |
146 | GetStdHandle (STD_INPUT_HANDLE),\r | |
147 | &Record,\r | |
148 | 1,\r | |
149 | &RecordNum\r | |
150 | );\r | |
151 | }\r | |
152 | }\r | |
153 | } while (Success);\r | |
154 | \r | |
3c859dfe RN |
155 | return FALSE;\r |
156 | }\r | |
157 | \r | |
158 | UINTN\r | |
159 | SecReadStdIn (\r | |
160 | IN UINT8 *Buffer,\r | |
161 | IN UINTN NumberOfBytes\r | |
162 | )\r | |
163 | {\r | |
5601e90d RN |
164 | BOOL Success;\r |
165 | INPUT_RECORD Record;\r | |
166 | DWORD RecordNum;\r | |
167 | UINTN BytesReturn;\r | |
168 | \r | |
169 | if (!SecPollStdIn ()) {\r | |
170 | return 0;\r | |
171 | }\r | |
172 | Success = ReadConsoleInput (\r | |
173 | GetStdHandle (STD_INPUT_HANDLE),\r | |
174 | &Record,\r | |
175 | 1,\r | |
176 | &RecordNum\r | |
177 | );\r | |
178 | ASSERT (Success && (RecordNum == 1) && (Record.EventType == KEY_EVENT) && (Record.Event.KeyEvent.bKeyDown));\r | |
179 | NumberOfBytes = MIN (Record.Event.KeyEvent.wRepeatCount, NumberOfBytes);\r | |
180 | BytesReturn = NumberOfBytes;\r | |
181 | while (NumberOfBytes-- != 0) {\r | |
182 | Buffer[NumberOfBytes] = Record.Event.KeyEvent.uChar.AsciiChar;\r | |
183 | }\r | |
184 | return BytesReturn;\r | |
3c859dfe RN |
185 | }\r |
186 | \r | |
187 | \r | |
188 | VOID *\r | |
189 | SecAlloc (\r | |
190 | IN UINTN Size\r | |
191 | )\r | |
192 | {\r | |
193 | return malloc ((size_t)Size);\r | |
194 | }\r | |
195 | \r | |
196 | BOOLEAN\r | |
197 | SecFree (\r | |
198 | IN VOID *Ptr\r | |
199 | )\r | |
200 | {\r | |
201 | if (EfiSystemMemoryRange (Ptr)) {\r | |
202 | // If an address range is in the EFI memory map it was alloced via EFI.\r | |
203 | // So don't free those ranges and let the caller know.\r | |
204 | return FALSE;\r | |
205 | }\r | |
206 | \r | |
207 | free (Ptr);\r | |
208 | return TRUE;\r | |
209 | }\r | |
210 | \r | |
269c5123 RN |
211 | \r |
212 | \r | |
213 | //\r | |
214 | // Define a global that we can use to shut down the NT timer thread when\r | |
215 | // the timer is canceled.\r | |
216 | //\r | |
217 | BOOLEAN mCancelTimerThread = FALSE;\r | |
218 | \r | |
219 | //\r | |
220 | // The notification function to call on every timer interrupt\r | |
221 | //\r | |
222 | EMU_SET_TIMER_CALLBACK *mTimerNotifyFunction = NULL;\r | |
223 | \r | |
224 | //\r | |
225 | // The thread handle for this driver\r | |
226 | //\r | |
227 | HANDLE mNtMainThreadHandle;\r | |
228 | \r | |
229 | //\r | |
230 | // The timer value from the last timer interrupt\r | |
231 | //\r | |
232 | UINT32 mNtLastTick;\r | |
233 | \r | |
234 | //\r | |
235 | // Critical section used to update varibles shared between the main thread and\r | |
236 | // the timer interrupt thread.\r | |
237 | //\r | |
238 | CRITICAL_SECTION mNtCriticalSection;\r | |
239 | \r | |
240 | //\r | |
241 | // Worker Functions\r | |
242 | //\r | |
243 | UINT mMMTimerThreadID = 0;\r | |
244 | \r | |
245 | volatile BOOLEAN mInterruptEnabled = FALSE;\r | |
246 | \r | |
247 | VOID\r | |
248 | CALLBACK\r | |
249 | MMTimerThread (\r | |
250 | UINT wTimerID,\r | |
251 | UINT msg,\r | |
252 | DWORD dwUser,\r | |
253 | DWORD dw1,\r | |
254 | DWORD dw2\r | |
255 | )\r | |
256 | {\r | |
257 | UINT32 CurrentTick;\r | |
258 | UINT32 Delta;\r | |
259 | \r | |
260 | if (!mCancelTimerThread) {\r | |
261 | \r | |
262 | //\r | |
263 | // Suspend the main thread until we are done.\r | |
264 | // Enter the critical section before suspending\r | |
265 | // and leave the critical section after resuming\r | |
266 | // to avoid deadlock between main and timer thread.\r | |
267 | //\r | |
268 | EnterCriticalSection (&mNtCriticalSection);\r | |
269 | SuspendThread (mNtMainThreadHandle);\r | |
270 | \r | |
271 | //\r | |
272 | // If the timer thread is being canceled, then bail immediately.\r | |
273 | // We check again here because there's a small window of time from when\r | |
274 | // this thread was kicked off and when we suspended the main thread above.\r | |
275 | //\r | |
276 | if (mCancelTimerThread) {\r | |
277 | ResumeThread (mNtMainThreadHandle);\r | |
278 | LeaveCriticalSection (&mNtCriticalSection);\r | |
279 | timeKillEvent (wTimerID);\r | |
280 | mMMTimerThreadID = 0;\r | |
281 | return;\r | |
282 | }\r | |
283 | \r | |
284 | while (!mInterruptEnabled) {\r | |
285 | //\r | |
286 | // Resume the main thread\r | |
287 | //\r | |
288 | ResumeThread (mNtMainThreadHandle);\r | |
289 | LeaveCriticalSection (&mNtCriticalSection);\r | |
290 | \r | |
291 | //\r | |
292 | // Wait for interrupts to be enabled.\r | |
293 | //\r | |
294 | while (!mInterruptEnabled) {\r | |
295 | Sleep (1);\r | |
296 | }\r | |
297 | \r | |
298 | //\r | |
299 | // Suspend the main thread until we are done\r | |
300 | //\r | |
301 | EnterCriticalSection (&mNtCriticalSection);\r | |
302 | SuspendThread (mNtMainThreadHandle);\r | |
303 | }\r | |
304 | \r | |
305 | //\r | |
306 | // Get the current system tick\r | |
307 | //\r | |
308 | CurrentTick = GetTickCount ();\r | |
309 | Delta = CurrentTick - mNtLastTick;\r | |
310 | mNtLastTick = CurrentTick;\r | |
311 | \r | |
312 | //\r | |
313 | // If delay was more then 1 second, ignore it (probably debugging case)\r | |
314 | //\r | |
315 | if (Delta < 1000) {\r | |
316 | \r | |
317 | //\r | |
318 | // Only invoke the callback function if a Non-NULL handler has been\r | |
319 | // registered. Assume all other handlers are legal.\r | |
320 | //\r | |
321 | if (mTimerNotifyFunction != NULL) {\r | |
322 | mTimerNotifyFunction (Delta);\r | |
323 | }\r | |
324 | }\r | |
325 | \r | |
326 | //\r | |
327 | // Resume the main thread\r | |
328 | //\r | |
329 | ResumeThread (mNtMainThreadHandle);\r | |
330 | LeaveCriticalSection (&mNtCriticalSection);\r | |
331 | } else {\r | |
332 | timeKillEvent (wTimerID);\r | |
333 | mMMTimerThreadID = 0;\r | |
334 | }\r | |
335 | \r | |
336 | }\r | |
337 | \r | |
3c859dfe RN |
338 | VOID\r |
339 | SecSetTimer (\r | |
340 | IN UINT64 TimerPeriod,\r | |
341 | IN EMU_SET_TIMER_CALLBACK Callback\r | |
342 | )\r | |
343 | {\r | |
269c5123 RN |
344 | //\r |
345 | // If TimerPeriod is 0, then the timer thread should be canceled\r | |
346 | //\r | |
347 | if (TimerPeriod == 0) {\r | |
348 | //\r | |
349 | // Cancel the timer thread\r | |
350 | //\r | |
351 | EnterCriticalSection (&mNtCriticalSection);\r | |
352 | \r | |
353 | mCancelTimerThread = TRUE;\r | |
354 | \r | |
355 | LeaveCriticalSection (&mNtCriticalSection);\r | |
356 | \r | |
357 | //\r | |
358 | // Wait for the timer thread to exit\r | |
359 | //\r | |
360 | \r | |
361 | if (mMMTimerThreadID != 0) {\r | |
362 | timeKillEvent (mMMTimerThreadID);\r | |
363 | mMMTimerThreadID = 0;\r | |
364 | }\r | |
365 | } else {\r | |
366 | //\r | |
367 | // If the TimerPeriod is valid, then create and/or adjust the period of the timer thread\r | |
368 | //\r | |
369 | EnterCriticalSection (&mNtCriticalSection);\r | |
370 | \r | |
371 | mCancelTimerThread = FALSE;\r | |
372 | \r | |
373 | LeaveCriticalSection (&mNtCriticalSection);\r | |
374 | \r | |
375 | //\r | |
376 | // Get the starting tick location if we are just starting the timer thread\r | |
377 | //\r | |
378 | mNtLastTick = GetTickCount ();\r | |
379 | \r | |
380 | if (mMMTimerThreadID) {\r | |
381 | timeKillEvent (mMMTimerThreadID);\r | |
382 | }\r | |
383 | \r | |
384 | SetThreadPriority (\r | |
385 | GetCurrentThread (),\r | |
386 | THREAD_PRIORITY_HIGHEST\r | |
387 | );\r | |
388 | \r | |
389 | mMMTimerThreadID = timeSetEvent (\r | |
390 | (UINT)TimerPeriod,\r | |
391 | 0,\r | |
392 | MMTimerThread,\r | |
393 | (DWORD_PTR)NULL,\r | |
394 | TIME_PERIODIC | TIME_KILL_SYNCHRONOUS | TIME_CALLBACK_FUNCTION\r | |
395 | );\r | |
396 | }\r | |
397 | mTimerNotifyFunction = Callback;\r | |
3c859dfe RN |
398 | }\r |
399 | \r | |
400 | VOID\r | |
401 | SecInitializeThunk (\r | |
402 | VOID\r | |
403 | )\r | |
404 | {\r | |
269c5123 RN |
405 | InitializeCriticalSection (&mNtCriticalSection);\r |
406 | \r | |
407 | DuplicateHandle (\r | |
408 | GetCurrentProcess (),\r | |
409 | GetCurrentThread (),\r | |
410 | GetCurrentProcess (),\r | |
411 | &mNtMainThreadHandle,\r | |
412 | 0,\r | |
413 | FALSE,\r | |
414 | DUPLICATE_SAME_ACCESS\r | |
415 | );\r | |
3c859dfe RN |
416 | }\r |
417 | \r | |
418 | VOID\r | |
419 | SecEnableInterrupt (\r | |
420 | VOID\r | |
421 | )\r | |
422 | {\r | |
269c5123 | 423 | mInterruptEnabled = TRUE;\r |
3c859dfe RN |
424 | }\r |
425 | \r | |
426 | \r | |
427 | VOID\r | |
428 | SecDisableInterrupt (\r | |
429 | VOID\r | |
430 | )\r | |
431 | {\r | |
269c5123 | 432 | mInterruptEnabled = FALSE;\r |
3c859dfe RN |
433 | }\r |
434 | \r | |
435 | \r | |
436 | UINT64\r | |
437 | SecQueryPerformanceFrequency (\r | |
438 | VOID\r | |
439 | )\r | |
440 | {\r | |
441 | // Hard code to nanoseconds\r | |
442 | return 1000000000ULL;\r | |
443 | }\r | |
444 | \r | |
445 | UINT64\r | |
446 | SecQueryPerformanceCounter (\r | |
447 | VOID\r | |
448 | )\r | |
449 | {\r | |
450 | return 0;\r | |
451 | }\r | |
452 | \r | |
453 | \r | |
454 | \r | |
455 | VOID\r | |
456 | SecSleep (\r | |
457 | IN UINT64 Nanoseconds\r | |
458 | )\r | |
459 | {\r | |
460 | Sleep ((DWORD)DivU64x32 (Nanoseconds, 1000000));\r | |
461 | }\r | |
462 | \r | |
463 | \r | |
464 | VOID\r | |
465 | SecCpuSleep (\r | |
466 | VOID\r | |
467 | )\r | |
468 | {\r | |
469 | Sleep (1);\r | |
470 | }\r | |
471 | \r | |
472 | \r | |
473 | VOID\r | |
474 | SecExit (\r | |
475 | UINTN Status\r | |
476 | )\r | |
477 | {\r | |
478 | exit ((int)Status);\r | |
479 | }\r | |
480 | \r | |
481 | \r | |
482 | VOID\r | |
483 | SecGetTime (\r | |
484 | OUT EFI_TIME *Time,\r | |
485 | OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL\r | |
486 | )\r | |
487 | {\r | |
07d8559c RN |
488 | SYSTEMTIME SystemTime;\r |
489 | TIME_ZONE_INFORMATION TimeZone;\r | |
490 | \r | |
491 | GetLocalTime (&SystemTime);\r | |
492 | GetTimeZoneInformation (&TimeZone);\r | |
493 | \r | |
494 | Time->Year = (UINT16)SystemTime.wYear;\r | |
495 | Time->Month = (UINT8)SystemTime.wMonth;\r | |
496 | Time->Day = (UINT8)SystemTime.wDay;\r | |
497 | Time->Hour = (UINT8)SystemTime.wHour;\r | |
498 | Time->Minute = (UINT8)SystemTime.wMinute;\r | |
499 | Time->Second = (UINT8)SystemTime.wSecond;\r | |
500 | Time->Nanosecond = (UINT32)(SystemTime.wMilliseconds * 1000000);\r | |
501 | Time->TimeZone = (INT16)TimeZone.Bias;\r | |
502 | \r | |
503 | if (Capabilities != NULL) {\r | |
504 | Capabilities->Resolution = 1;\r | |
505 | Capabilities->Accuracy = 50000000;\r | |
506 | Capabilities->SetsToZero = FALSE;\r | |
507 | }\r | |
508 | \r | |
509 | Time->Daylight = 0;\r | |
510 | if (TimeZone.StandardDate.wMonth) {\r | |
511 | Time->Daylight = (UINT8)TimeZone.StandardDate.wMonth;\r | |
512 | }\r | |
3c859dfe RN |
513 | }\r |
514 | \r | |
515 | EFI_STATUS\r | |
516 | SecSetTime (\r | |
517 | IN EFI_TIME *Time\r | |
07d8559c | 518 | )\r |
3c859dfe | 519 | {\r |
07d8559c RN |
520 | TIME_ZONE_INFORMATION TimeZone;\r |
521 | SYSTEMTIME SystemTime;\r | |
522 | BOOL Flag;\r | |
523 | \r | |
524 | //\r | |
525 | // Set Daylight savings time information and Time Zone\r | |
526 | //\r | |
527 | GetTimeZoneInformation (&TimeZone);\r | |
528 | TimeZone.StandardDate.wMonth = Time->Daylight;\r | |
529 | TimeZone.Bias = Time->TimeZone;\r | |
530 | Flag = SetTimeZoneInformation (&TimeZone);\r | |
531 | if (!Flag) {\r | |
532 | return EFI_DEVICE_ERROR;\r | |
533 | }\r | |
534 | \r | |
535 | SystemTime.wYear = Time->Year;\r | |
536 | SystemTime.wMonth = Time->Month;\r | |
537 | SystemTime.wDay = Time->Day;\r | |
538 | SystemTime.wHour = Time->Hour;\r | |
539 | SystemTime.wMinute = Time->Minute;\r | |
540 | SystemTime.wSecond = Time->Second;\r | |
541 | SystemTime.wMilliseconds = (INT16)(Time->Nanosecond / 1000000);\r | |
542 | \r | |
543 | Flag = SetLocalTime (&SystemTime);\r | |
544 | \r | |
545 | if (!Flag) {\r | |
546 | return EFI_DEVICE_ERROR;\r | |
547 | } else {\r | |
548 | return EFI_SUCCESS;\r | |
549 | }\r | |
3c859dfe RN |
550 | }\r |
551 | \r | |
552 | EMU_THUNK_PROTOCOL gEmuThunkProtocol = {\r | |
553 | SecWriteStdErr,\r | |
554 | SecConfigStdIn,\r | |
555 | SecWriteStdOut,\r | |
556 | SecReadStdIn,\r | |
557 | SecPollStdIn,\r | |
558 | SecAlloc,\r | |
559 | NULL,\r | |
560 | SecFree,\r | |
561 | SecPeCoffGetEntryPoint,\r | |
562 | PeCoffLoaderRelocateImageExtraAction,\r | |
563 | PeCoffLoaderUnloadImageExtraAction,\r | |
564 | SecEnableInterrupt,\r | |
565 | SecDisableInterrupt,\r | |
566 | SecQueryPerformanceFrequency,\r | |
567 | SecQueryPerformanceCounter,\r | |
568 | SecSleep,\r | |
569 | SecCpuSleep,\r | |
570 | SecExit,\r | |
571 | SecGetTime,\r | |
572 | SecSetTime,\r | |
573 | SecSetTimer,\r | |
574 | GetNextThunkProtocol\r | |
575 | };\r | |
576 | \r | |
577 | \r | |
578 | #pragma warning(default : 4996)\r | |
579 | #pragma warning(default : 4232)\r | |
580 | \r |