]> git.proxmox.com Git - mirror_edk2.git/blob - EmulatorPkg/Win/Host/WinThunk.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 EFI_STATUS
55 SecConfigStdIn (
56 VOID
57 )
58 {
59 BOOL Success;
60 DWORD Mode;
61
62 Success = GetConsoleMode (GetStdHandle (STD_INPUT_HANDLE), &Mode);
63 if (Success) {
64 //
65 // Disable buffer (line input), echo, mouse, window
66 //
67 Mode &= ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT);
68
69 #if defined (NTDDI_VERSION) && defined (NTDDI_WIN10_TH2) && (NTDDI_VERSION > NTDDI_WIN10_TH2)
70 //
71 // Enable virtual terminal input for Win10 above TH2
72 //
73 Mode |= ENABLE_VIRTUAL_TERMINAL_INPUT;
74 #endif
75
76 Success = SetConsoleMode (GetStdHandle (STD_INPUT_HANDLE), Mode);
77 }
78
79 #if defined (NTDDI_VERSION) && defined (NTDDI_WIN10_TH2) && (NTDDI_VERSION > NTDDI_WIN10_TH2)
80 //
81 // Enable terminal mode for Win10 above TH2
82 //
83 if (Success) {
84 Success = GetConsoleMode (GetStdHandle (STD_OUTPUT_HANDLE), &Mode);
85 if (Success) {
86 Success = SetConsoleMode (
87 GetStdHandle (STD_OUTPUT_HANDLE),
88 Mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN
89 );
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
133 Success = PeekConsoleInput (
134 GetStdHandle (STD_INPUT_HANDLE),
135 &Record,
136 1,
137 &RecordNum
138 );
139 if (Success && (RecordNum == 1)) {
140 if ((Record.EventType == KEY_EVENT) && Record.Event.KeyEvent.bKeyDown) {
141 return TRUE;
142 } else {
143 //
144 // Consume the non-key event.
145 //
146 Success = ReadConsoleInput (
147 GetStdHandle (STD_INPUT_HANDLE),
148 &Record,
149 1,
150 &RecordNum
151 );
152 }
153 }
154 } while (Success);
155
156 return FALSE;
157 }
158
159 UINTN
160 SecReadStdIn (
161 IN UINT8 *Buffer,
162 IN UINTN NumberOfBytes
163 )
164 {
165 BOOL Success;
166 INPUT_RECORD Record;
167 DWORD RecordNum;
168 UINTN BytesReturn;
169
170 if (!SecPollStdIn ()) {
171 return 0;
172 }
173
174 Success = ReadConsoleInput (
175 GetStdHandle (STD_INPUT_HANDLE),
176 &Record,
177 1,
178 &RecordNum
179 );
180 ASSERT (Success && (RecordNum == 1) && (Record.EventType == KEY_EVENT) && (Record.Event.KeyEvent.bKeyDown));
181 NumberOfBytes = MIN (Record.Event.KeyEvent.wRepeatCount, NumberOfBytes);
182 BytesReturn = NumberOfBytes;
183 while (NumberOfBytes-- != 0) {
184 Buffer[NumberOfBytes] = Record.Event.KeyEvent.uChar.AsciiChar;
185 }
186
187 return BytesReturn;
188 }
189
190 VOID *
191 SecAlloc (
192 IN UINTN Size
193 )
194 {
195 return malloc ((size_t)Size);
196 }
197
198 BOOLEAN
199 SecFree (
200 IN VOID *Ptr
201 )
202 {
203 if (EfiSystemMemoryRange (Ptr)) {
204 // If an address range is in the EFI memory map it was alloced via EFI.
205 // So don't free those ranges and let the caller know.
206 return FALSE;
207 }
208
209 free (Ptr);
210 return TRUE;
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 // Suspend the main thread until we are done.
263 // Enter the critical section before suspending
264 // and leave the critical section after resuming
265 // to avoid deadlock between main and timer thread.
266 //
267 EnterCriticalSection (&mNtCriticalSection);
268 SuspendThread (mNtMainThreadHandle);
269
270 //
271 // If the timer thread is being canceled, then bail immediately.
272 // We check again here because there's a small window of time from when
273 // this thread was kicked off and when we suspended the main thread above.
274 //
275 if (mCancelTimerThread) {
276 ResumeThread (mNtMainThreadHandle);
277 LeaveCriticalSection (&mNtCriticalSection);
278 timeKillEvent (wTimerID);
279 mMMTimerThreadID = 0;
280 return;
281 }
282
283 while (!mInterruptEnabled) {
284 //
285 // Resume the main thread
286 //
287 ResumeThread (mNtMainThreadHandle);
288 LeaveCriticalSection (&mNtCriticalSection);
289
290 //
291 // Wait for interrupts to be enabled.
292 //
293 while (!mInterruptEnabled) {
294 Sleep (1);
295 }
296
297 //
298 // Suspend the main thread until we are done
299 //
300 EnterCriticalSection (&mNtCriticalSection);
301 SuspendThread (mNtMainThreadHandle);
302 }
303
304 //
305 // Get the current system tick
306 //
307 CurrentTick = GetTickCount ();
308 Delta = CurrentTick - mNtLastTick;
309 mNtLastTick = CurrentTick;
310
311 //
312 // If delay was more then 1 second, ignore it (probably debugging case)
313 //
314 if (Delta < 1000) {
315 //
316 // Only invoke the callback function if a Non-NULL handler has been
317 // registered. Assume all other handlers are legal.
318 //
319 if (mTimerNotifyFunction != NULL) {
320 mTimerNotifyFunction (Delta);
321 }
322 }
323
324 //
325 // Resume the main thread
326 //
327 ResumeThread (mNtMainThreadHandle);
328 LeaveCriticalSection (&mNtCriticalSection);
329 } else {
330 timeKillEvent (wTimerID);
331 mMMTimerThreadID = 0;
332 }
333 }
334
335 VOID
336 SecSetTimer (
337 IN UINT64 TimerPeriod,
338 IN EMU_SET_TIMER_CALLBACK Callback
339 )
340 {
341 //
342 // If TimerPeriod is 0, then the timer thread should be canceled
343 //
344 if (TimerPeriod == 0) {
345 //
346 // Cancel the timer thread
347 //
348 EnterCriticalSection (&mNtCriticalSection);
349
350 mCancelTimerThread = TRUE;
351
352 LeaveCriticalSection (&mNtCriticalSection);
353
354 //
355 // Wait for the timer thread to exit
356 //
357
358 if (mMMTimerThreadID != 0) {
359 timeKillEvent (mMMTimerThreadID);
360 mMMTimerThreadID = 0;
361 }
362 } else {
363 //
364 // If the TimerPeriod is valid, then create and/or adjust the period of the timer thread
365 //
366 EnterCriticalSection (&mNtCriticalSection);
367
368 mCancelTimerThread = FALSE;
369
370 LeaveCriticalSection (&mNtCriticalSection);
371
372 //
373 // Get the starting tick location if we are just starting the timer thread
374 //
375 mNtLastTick = GetTickCount ();
376
377 if (mMMTimerThreadID) {
378 timeKillEvent (mMMTimerThreadID);
379 }
380
381 SetThreadPriority (
382 GetCurrentThread (),
383 THREAD_PRIORITY_HIGHEST
384 );
385
386 mMMTimerThreadID = timeSetEvent (
387 (UINT)TimerPeriod,
388 0,
389 MMTimerThread,
390 (DWORD_PTR)NULL,
391 TIME_PERIODIC | TIME_KILL_SYNCHRONOUS | TIME_CALLBACK_FUNCTION
392 );
393 }
394
395 mTimerNotifyFunction = Callback;
396 }
397
398 VOID
399 SecInitializeThunk (
400 VOID
401 )
402 {
403 InitializeCriticalSection (&mNtCriticalSection);
404
405 DuplicateHandle (
406 GetCurrentProcess (),
407 GetCurrentThread (),
408 GetCurrentProcess (),
409 &mNtMainThreadHandle,
410 0,
411 FALSE,
412 DUPLICATE_SAME_ACCESS
413 );
414 }
415
416 VOID
417 SecEnableInterrupt (
418 VOID
419 )
420 {
421 mInterruptEnabled = TRUE;
422 }
423
424 VOID
425 SecDisableInterrupt (
426 VOID
427 )
428 {
429 mInterruptEnabled = FALSE;
430 }
431
432 UINT64
433 SecQueryPerformanceFrequency (
434 VOID
435 )
436 {
437 // Hard code to nanoseconds
438 return 1000000000ULL;
439 }
440
441 UINT64
442 SecQueryPerformanceCounter (
443 VOID
444 )
445 {
446 return 0;
447 }
448
449 VOID
450 SecSleep (
451 IN UINT64 Nanoseconds
452 )
453 {
454 Sleep ((DWORD)DivU64x32 (Nanoseconds, 1000000));
455 }
456
457 VOID
458 SecCpuSleep (
459 VOID
460 )
461 {
462 Sleep (1);
463 }
464
465 VOID
466 SecExit (
467 UINTN Status
468 )
469 {
470 exit ((int)Status);
471 }
472
473 VOID
474 SecGetTime (
475 OUT EFI_TIME *Time,
476 OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
477 )
478 {
479 SYSTEMTIME SystemTime;
480 TIME_ZONE_INFORMATION TimeZone;
481
482 GetLocalTime (&SystemTime);
483 GetTimeZoneInformation (&TimeZone);
484
485 Time->Year = (UINT16)SystemTime.wYear;
486 Time->Month = (UINT8)SystemTime.wMonth;
487 Time->Day = (UINT8)SystemTime.wDay;
488 Time->Hour = (UINT8)SystemTime.wHour;
489 Time->Minute = (UINT8)SystemTime.wMinute;
490 Time->Second = (UINT8)SystemTime.wSecond;
491 Time->Nanosecond = (UINT32)(SystemTime.wMilliseconds * 1000000);
492 Time->TimeZone = (INT16)TimeZone.Bias;
493
494 if (Capabilities != NULL) {
495 Capabilities->Resolution = 1;
496 Capabilities->Accuracy = 50000000;
497 Capabilities->SetsToZero = FALSE;
498 }
499
500 Time->Daylight = 0;
501 if (TimeZone.StandardDate.wMonth) {
502 Time->Daylight = (UINT8)TimeZone.StandardDate.wMonth;
503 }
504 }
505
506 EFI_STATUS
507 SecSetTime (
508 IN EFI_TIME *Time
509 )
510 {
511 TIME_ZONE_INFORMATION TimeZone;
512 SYSTEMTIME SystemTime;
513 BOOL Flag;
514
515 //
516 // Set Daylight savings time information and Time Zone
517 //
518 GetTimeZoneInformation (&TimeZone);
519 TimeZone.StandardDate.wMonth = Time->Daylight;
520 TimeZone.Bias = Time->TimeZone;
521 Flag = SetTimeZoneInformation (&TimeZone);
522 if (!Flag) {
523 return EFI_DEVICE_ERROR;
524 }
525
526 SystemTime.wYear = Time->Year;
527 SystemTime.wMonth = Time->Month;
528 SystemTime.wDay = Time->Day;
529 SystemTime.wHour = Time->Hour;
530 SystemTime.wMinute = Time->Minute;
531 SystemTime.wSecond = Time->Second;
532 SystemTime.wMilliseconds = (INT16)(Time->Nanosecond / 1000000);
533
534 Flag = SetLocalTime (&SystemTime);
535
536 if (!Flag) {
537 return EFI_DEVICE_ERROR;
538 } else {
539 return EFI_SUCCESS;
540 }
541 }
542
543 EMU_THUNK_PROTOCOL gEmuThunkProtocol = {
544 SecWriteStdErr,
545 SecConfigStdIn,
546 SecWriteStdOut,
547 SecReadStdIn,
548 SecPollStdIn,
549 SecAlloc,
550 NULL,
551 SecFree,
552 SecPeCoffGetEntryPoint,
553 PeCoffLoaderRelocateImageExtraAction,
554 PeCoffLoaderUnloadImageExtraAction,
555 SecEnableInterrupt,
556 SecDisableInterrupt,
557 SecQueryPerformanceFrequency,
558 SecQueryPerformanceCounter,
559 SecSleep,
560 SecCpuSleep,
561 SecExit,
562 SecGetTime,
563 SecSetTime,
564 SecSetTimer,
565 GetNextThunkProtocol
566 };
567
568 #pragma warning(default : 4996)
569 #pragma warning(default : 4232)