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