]> git.proxmox.com Git - mirror_edk2.git/blob - EmulatorPkg/Win/Host/WinThunk.c
ffe71aef9a1a61b843abdd8522ce95a2006a16dc
[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 Success = SetConsoleMode (
75 GetStdHandle (STD_INPUT_HANDLE),
76 Mode | ENABLE_VIRTUAL_TERMINAL_INPUT & ~(ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT | ENABLE_MOUSE_INPUT | ENABLE_WINDOW_INPUT)
77 );
78 }
79 if (Success) {
80 //
81 // Enable terminal mode
82 //
83 Success = GetConsoleMode (GetStdHandle (STD_OUTPUT_HANDLE), &Mode);
84 if (Success) {
85 Success = SetConsoleMode (
86 GetStdHandle (STD_OUTPUT_HANDLE),
87 Mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING | DISABLE_NEWLINE_AUTO_RETURN
88 );
89 }
90 }
91 return Success ? EFI_SUCCESS : EFI_DEVICE_ERROR;
92 }
93
94 UINTN
95 SecWriteStdOut (
96 IN UINT8 *Buffer,
97 IN UINTN NumberOfBytes
98 )
99 {
100 BOOL Success;
101 DWORD CharCount;
102
103 CharCount = (DWORD)NumberOfBytes;
104 Success = WriteFile (
105 GetStdHandle (STD_OUTPUT_HANDLE),
106 Buffer,
107 CharCount,
108 &CharCount,
109 NULL
110 );
111
112 return Success ? CharCount : 0;
113 }
114
115 BOOLEAN
116 SecPollStdIn (
117 VOID
118 )
119 {
120 BOOL Success;
121 INPUT_RECORD Record;
122 DWORD RecordNum;
123
124 do {
125 Success = GetNumberOfConsoleInputEvents (GetStdHandle (STD_INPUT_HANDLE), &RecordNum);
126 if (!Success || (RecordNum == 0)) {
127 break;
128 }
129 Success = PeekConsoleInput (
130 GetStdHandle (STD_INPUT_HANDLE),
131 &Record,
132 1,
133 &RecordNum
134 );
135 if (Success && (RecordNum == 1)) {
136 if (Record.EventType == KEY_EVENT && Record.Event.KeyEvent.bKeyDown) {
137 return TRUE;
138 } else {
139 //
140 // Consume the non-key event.
141 //
142 Success = ReadConsoleInput (
143 GetStdHandle (STD_INPUT_HANDLE),
144 &Record,
145 1,
146 &RecordNum
147 );
148 }
149 }
150 } while (Success);
151
152 return FALSE;
153 }
154
155 UINTN
156 SecReadStdIn (
157 IN UINT8 *Buffer,
158 IN UINTN NumberOfBytes
159 )
160 {
161 BOOL Success;
162 INPUT_RECORD Record;
163 DWORD RecordNum;
164 UINTN BytesReturn;
165
166 if (!SecPollStdIn ()) {
167 return 0;
168 }
169 Success = ReadConsoleInput (
170 GetStdHandle (STD_INPUT_HANDLE),
171 &Record,
172 1,
173 &RecordNum
174 );
175 ASSERT (Success && (RecordNum == 1) && (Record.EventType == KEY_EVENT) && (Record.Event.KeyEvent.bKeyDown));
176 NumberOfBytes = MIN (Record.Event.KeyEvent.wRepeatCount, NumberOfBytes);
177 BytesReturn = NumberOfBytes;
178 while (NumberOfBytes-- != 0) {
179 Buffer[NumberOfBytes] = Record.Event.KeyEvent.uChar.AsciiChar;
180 }
181 return BytesReturn;
182 }
183
184
185 VOID *
186 SecAlloc (
187 IN UINTN Size
188 )
189 {
190 return malloc ((size_t)Size);
191 }
192
193 BOOLEAN
194 SecFree (
195 IN VOID *Ptr
196 )
197 {
198 if (EfiSystemMemoryRange (Ptr)) {
199 // If an address range is in the EFI memory map it was alloced via EFI.
200 // So don't free those ranges and let the caller know.
201 return FALSE;
202 }
203
204 free (Ptr);
205 return TRUE;
206 }
207
208
209
210 //
211 // Define a global that we can use to shut down the NT timer thread when
212 // the timer is canceled.
213 //
214 BOOLEAN mCancelTimerThread = FALSE;
215
216 //
217 // The notification function to call on every timer interrupt
218 //
219 EMU_SET_TIMER_CALLBACK *mTimerNotifyFunction = NULL;
220
221 //
222 // The thread handle for this driver
223 //
224 HANDLE mNtMainThreadHandle;
225
226 //
227 // The timer value from the last timer interrupt
228 //
229 UINT32 mNtLastTick;
230
231 //
232 // Critical section used to update varibles shared between the main thread and
233 // the timer interrupt thread.
234 //
235 CRITICAL_SECTION mNtCriticalSection;
236
237 //
238 // Worker Functions
239 //
240 UINT mMMTimerThreadID = 0;
241
242 volatile BOOLEAN mInterruptEnabled = FALSE;
243
244 VOID
245 CALLBACK
246 MMTimerThread (
247 UINT wTimerID,
248 UINT msg,
249 DWORD dwUser,
250 DWORD dw1,
251 DWORD dw2
252 )
253 {
254 UINT32 CurrentTick;
255 UINT32 Delta;
256
257 if (!mCancelTimerThread) {
258
259 //
260 // Suspend the main thread until we are done.
261 // Enter the critical section before suspending
262 // and leave the critical section after resuming
263 // to avoid deadlock between main and timer thread.
264 //
265 EnterCriticalSection (&mNtCriticalSection);
266 SuspendThread (mNtMainThreadHandle);
267
268 //
269 // If the timer thread is being canceled, then bail immediately.
270 // We check again here because there's a small window of time from when
271 // this thread was kicked off and when we suspended the main thread above.
272 //
273 if (mCancelTimerThread) {
274 ResumeThread (mNtMainThreadHandle);
275 LeaveCriticalSection (&mNtCriticalSection);
276 timeKillEvent (wTimerID);
277 mMMTimerThreadID = 0;
278 return;
279 }
280
281 while (!mInterruptEnabled) {
282 //
283 // Resume the main thread
284 //
285 ResumeThread (mNtMainThreadHandle);
286 LeaveCriticalSection (&mNtCriticalSection);
287
288 //
289 // Wait for interrupts to be enabled.
290 //
291 while (!mInterruptEnabled) {
292 Sleep (1);
293 }
294
295 //
296 // Suspend the main thread until we are done
297 //
298 EnterCriticalSection (&mNtCriticalSection);
299 SuspendThread (mNtMainThreadHandle);
300 }
301
302 //
303 // Get the current system tick
304 //
305 CurrentTick = GetTickCount ();
306 Delta = CurrentTick - mNtLastTick;
307 mNtLastTick = CurrentTick;
308
309 //
310 // If delay was more then 1 second, ignore it (probably debugging case)
311 //
312 if (Delta < 1000) {
313
314 //
315 // Only invoke the callback function if a Non-NULL handler has been
316 // registered. Assume all other handlers are legal.
317 //
318 if (mTimerNotifyFunction != NULL) {
319 mTimerNotifyFunction (Delta);
320 }
321 }
322
323 //
324 // Resume the main thread
325 //
326 ResumeThread (mNtMainThreadHandle);
327 LeaveCriticalSection (&mNtCriticalSection);
328 } else {
329 timeKillEvent (wTimerID);
330 mMMTimerThreadID = 0;
331 }
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 mTimerNotifyFunction = Callback;
395 }
396
397 VOID
398 SecInitializeThunk (
399 VOID
400 )
401 {
402 InitializeCriticalSection (&mNtCriticalSection);
403
404 DuplicateHandle (
405 GetCurrentProcess (),
406 GetCurrentThread (),
407 GetCurrentProcess (),
408 &mNtMainThreadHandle,
409 0,
410 FALSE,
411 DUPLICATE_SAME_ACCESS
412 );
413 }
414
415 VOID
416 SecEnableInterrupt (
417 VOID
418 )
419 {
420 mInterruptEnabled = TRUE;
421 }
422
423
424 VOID
425 SecDisableInterrupt (
426 VOID
427 )
428 {
429 mInterruptEnabled = FALSE;
430 }
431
432
433 UINT64
434 SecQueryPerformanceFrequency (
435 VOID
436 )
437 {
438 // Hard code to nanoseconds
439 return 1000000000ULL;
440 }
441
442 UINT64
443 SecQueryPerformanceCounter (
444 VOID
445 )
446 {
447 return 0;
448 }
449
450
451
452 VOID
453 SecSleep (
454 IN UINT64 Nanoseconds
455 )
456 {
457 Sleep ((DWORD)DivU64x32 (Nanoseconds, 1000000));
458 }
459
460
461 VOID
462 SecCpuSleep (
463 VOID
464 )
465 {
466 Sleep (1);
467 }
468
469
470 VOID
471 SecExit (
472 UINTN Status
473 )
474 {
475 exit ((int)Status);
476 }
477
478
479 VOID
480 SecGetTime (
481 OUT EFI_TIME *Time,
482 OUT EFI_TIME_CAPABILITIES *Capabilities OPTIONAL
483 )
484 {
485 }
486
487 EFI_STATUS
488 SecSetTime (
489 IN EFI_TIME *Time
490 )
491 {
492 return EFI_SUCCESS;
493 }
494
495 EMU_THUNK_PROTOCOL gEmuThunkProtocol = {
496 SecWriteStdErr,
497 SecConfigStdIn,
498 SecWriteStdOut,
499 SecReadStdIn,
500 SecPollStdIn,
501 SecAlloc,
502 NULL,
503 SecFree,
504 SecPeCoffGetEntryPoint,
505 PeCoffLoaderRelocateImageExtraAction,
506 PeCoffLoaderUnloadImageExtraAction,
507 SecEnableInterrupt,
508 SecDisableInterrupt,
509 SecQueryPerformanceFrequency,
510 SecQueryPerformanceCounter,
511 SecSleep,
512 SecCpuSleep,
513 SecExit,
514 SecGetTime,
515 SecSetTime,
516 SecSetTimer,
517 GetNextThunkProtocol
518 };
519
520
521 #pragma warning(default : 4996)
522 #pragma warning(default : 4232)
523