]> git.proxmox.com Git - mirror_edk2.git/blame - EmulatorPkg/Win/Host/WinThunk.c
EmulatorPkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / EmulatorPkg / Win / Host / WinThunk.c
CommitLineData
3c859dfe
RN
1/**@file\r
2\r
3Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
e3ba31da 4SPDX-License-Identifier: BSD-2-Clause-Patent\r
3c859dfe
RN
5\r
6Module Name:\r
7\r
8 WinNtThunk.c\r
9\r
10Abstract:\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
33UINTN\r
34SecWriteStdErr (\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
55EFI_STATUS\r
56SecConfigStdIn (\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
97UINTN\r
98SecWriteStdOut (\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
118BOOLEAN\r
119SecPollStdIn (\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
158UINTN\r
159SecReadStdIn (\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
188VOID *\r
189SecAlloc (\r
190 IN UINTN Size\r
191 )\r
192{\r
193 return malloc ((size_t)Size);\r
194}\r
195\r
196BOOLEAN\r
197SecFree (\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
217BOOLEAN mCancelTimerThread = FALSE;\r
218\r
219//\r
220// The notification function to call on every timer interrupt\r
221//\r
222EMU_SET_TIMER_CALLBACK *mTimerNotifyFunction = NULL;\r
223\r
224//\r
225// The thread handle for this driver\r
226//\r
227HANDLE mNtMainThreadHandle;\r
228\r
229//\r
230// The timer value from the last timer interrupt\r
231//\r
232UINT32 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
238CRITICAL_SECTION mNtCriticalSection;\r
239\r
240//\r
241// Worker Functions\r
242//\r
243UINT mMMTimerThreadID = 0;\r
244\r
245volatile BOOLEAN mInterruptEnabled = FALSE;\r
246\r
247VOID\r
248CALLBACK\r
249MMTimerThread (\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
338VOID\r
339SecSetTimer (\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
400VOID\r
401SecInitializeThunk (\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
418VOID\r
419SecEnableInterrupt (\r
420 VOID\r
421 )\r
422{\r
269c5123 423 mInterruptEnabled = TRUE;\r
3c859dfe
RN
424}\r
425\r
426\r
427VOID\r
428SecDisableInterrupt (\r
429 VOID\r
430 )\r
431{\r
269c5123 432 mInterruptEnabled = FALSE;\r
3c859dfe
RN
433}\r
434\r
435\r
436UINT64\r
437SecQueryPerformanceFrequency (\r
438 VOID\r
439 )\r
440{\r
441 // Hard code to nanoseconds\r
442 return 1000000000ULL;\r
443}\r
444\r
445UINT64\r
446SecQueryPerformanceCounter (\r
447 VOID\r
448 )\r
449{\r
450 return 0;\r
451}\r
452\r
453\r
454\r
455VOID\r
456SecSleep (\r
457 IN UINT64 Nanoseconds\r
458 )\r
459{\r
460 Sleep ((DWORD)DivU64x32 (Nanoseconds, 1000000));\r
461}\r
462\r
463\r
464VOID\r
465SecCpuSleep (\r
466 VOID\r
467 )\r
468{\r
469 Sleep (1);\r
470}\r
471\r
472\r
473VOID\r
474SecExit (\r
475 UINTN Status\r
476 )\r
477{\r
478 exit ((int)Status);\r
479}\r
480\r
481\r
482VOID\r
483SecGetTime (\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
515EFI_STATUS\r
516SecSetTime (\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
552EMU_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