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