xref: /reactos/boot/environ/lib/firmware/efi/firmware.c (revision 9393fc32)
1 /*
2  * COPYRIGHT:       See COPYING.ARM in the top level directory
3  * PROJECT:         ReactOS UEFI Boot Library
4  * FILE:            boot/environ/lib/firmware/efi/firmware.c
5  * PURPOSE:         Boot Library Firmware Initialization for EFI
6  * PROGRAMMER:      Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include "bl.h"
12 
13 /* DATA VARIABLES ************************************************************/
14 
15 PBL_FIRMWARE_DESCRIPTOR EfiFirmwareParameters;
16 BL_FIRMWARE_DESCRIPTOR EfiFirmwareData;
17 EFI_HANDLE EfiImageHandle;
18 EFI_SYSTEM_TABLE* EfiSystemTable;
19 
20 EFI_SYSTEM_TABLE *EfiST;
21 EFI_BOOT_SERVICES *EfiBS;
22 EFI_RUNTIME_SERVICES *EfiRT;
23 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *EfiConOut;
24 EFI_SIMPLE_TEXT_INPUT_PROTOCOL *EfiConIn;
25 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *EfiConInEx;
26 PHYSICAL_ADDRESS EfiRsdt;
27 
28 EFI_GUID EfiGraphicsOutputProtocol = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
29 EFI_GUID EfiUgaDrawProtocol = EFI_UGA_DRAW_PROTOCOL_GUID;
30 EFI_GUID EfiLoadedImageProtocol = EFI_LOADED_IMAGE_PROTOCOL_GUID;
31 EFI_GUID EfiDevicePathProtocol = EFI_DEVICE_PATH_PROTOCOL_GUID;
32 EFI_GUID EfiSimpleTextInputExProtocol = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID;
33 EFI_GUID EfiBlockIoProtocol = EFI_BLOCK_IO_PROTOCOL_GUID;
34 EFI_GUID EfiRootAcpiTableGuid = EFI_ACPI_20_TABLE_GUID;
35 EFI_GUID EfiRootAcpiTable10Guid = EFI_ACPI_TABLE_GUID;
36 EFI_GUID EfiGlobalVariable = EFI_GLOBAL_VARIABLE;
37 EFI_GUID BlpEfiSecureBootPrivateNamespace = { 0x77FA9ABD , 0x0359, 0x4D32, { 0xBD, 0x60, 0x28, 0xF4, 0xE7, 0x8F, 0x78, 0x4B } };
38 
39 WCHAR BlScratchBuffer[8192];
40 
41 BOOLEAN BlpFirmwareChecked;
42 BOOLEAN BlpFirmwareEnabled;
43 
44 /* FUNCTIONS *****************************************************************/
45 
46 EFI_DEVICE_PATH *
EfiIsDevicePathParent(_In_ EFI_DEVICE_PATH * DevicePath1,_In_ EFI_DEVICE_PATH * DevicePath2)47 EfiIsDevicePathParent (
48     _In_ EFI_DEVICE_PATH *DevicePath1,
49     _In_ EFI_DEVICE_PATH *DevicePath2
50     )
51 {
52     EFI_DEVICE_PATH* CurrentPath1;
53     EFI_DEVICE_PATH* CurrentPath2;
54     USHORT Length1, Length2;
55 
56     /* Start with the current nodes */
57     CurrentPath1 = DevicePath1;
58     CurrentPath2 = DevicePath2;
59 
60     /* Loop each element of the device path */
61     while (!(IsDevicePathEndType(CurrentPath1)) &&
62            !(IsDevicePathEndType(CurrentPath2)))
63     {
64         /* Check if the element has a different length */
65         Length1 = DevicePathNodeLength(CurrentPath1);
66         Length2 = DevicePathNodeLength(CurrentPath2);
67         if (Length1 != Length2)
68         {
69             /* Then they're not related */
70             return NULL;
71         }
72 
73         /* Check if the rest of the element data matches */
74         if (RtlCompareMemory(CurrentPath1, CurrentPath2, Length1) != Length1)
75         {
76             /* Nope, not related */
77             return NULL;
78         }
79 
80         /* Move to the next element */
81         CurrentPath1 = NextDevicePathNode(CurrentPath1);
82         CurrentPath2 = NextDevicePathNode(CurrentPath2);
83     }
84 
85     /* If the last element in path 1 is empty, then path 2 is the child (deeper) */
86     if (!IsDevicePathEndType(CurrentPath1))
87     {
88         return DevicePath2;
89     }
90 
91     /* If the last element in path 2 is empty, then path 1 is the child (deeper) */
92     if (!IsDevicePathEndType(CurrentPath2))
93     {
94         return DevicePath1;
95     }
96 
97     /* They're both the end, so they're identical, so there's no parent */
98     return NULL;
99 }
100 
101 EFI_DEVICE_PATH*
EfiGetLeafNode(_In_ EFI_DEVICE_PATH * DevicePath)102 EfiGetLeafNode (
103     _In_ EFI_DEVICE_PATH *DevicePath
104     )
105 {
106     EFI_DEVICE_PATH *NextDevicePath;
107 
108     /* Make sure we're not already at the end */
109     if (!IsDevicePathEndType(DevicePath))
110     {
111         /* Grab the next node element, and keep going until the end */
112         for (NextDevicePath = NextDevicePathNode(DevicePath);
113              !IsDevicePathEndType(NextDevicePath);
114              NextDevicePath = NextDevicePathNode(NextDevicePath))
115         {
116             /* Save the current node we're at  */
117             DevicePath = NextDevicePath;
118         }
119     }
120 
121     /* This now contains the deepest (leaf) node */
122     return DevicePath;
123 }
124 
125 VOID
EfiPrintf(_In_ PWCHAR Format,...)126 EfiPrintf (
127     _In_ PWCHAR Format,
128     ...
129     )
130 {
131     va_list args;
132     va_start(args, Format);
133 
134     /* Capture the buffer in our scratch pad, and NULL-terminate */
135     vsnwprintf(BlScratchBuffer, RTL_NUMBER_OF(BlScratchBuffer) - 1, Format, args);
136     BlScratchBuffer[RTL_NUMBER_OF(BlScratchBuffer) - 1] = UNICODE_NULL;
137 
138     /* Check which mode we're in */
139     if (CurrentExecutionContext->Mode == BlRealMode)
140     {
141         /* Call EFI directly */
142         EfiConOut->OutputString(EfiConOut, BlScratchBuffer);
143     }
144     else
145     {
146         /* Switch to real mode */
147         BlpArchSwitchContext(BlRealMode);
148 
149         /* Call EFI directly */
150         if (EfiConOut != NULL)
151         {
152             EfiConOut->OutputString(EfiConOut, BlScratchBuffer);
153         }
154 
155         /* Switch back to protected mode */
156         BlpArchSwitchContext(BlProtectedMode);
157     }
158 
159     /* All done */
160     va_end(args);
161 }
162 
163 BOOLEAN EfiProtHashTableInitialized;
164 ULONG EfiProtHashTableId;
165 
166 typedef struct _BL_EFI_PROTOCOL
167 {
168     LIST_ENTRY ListEntry;
169     EFI_GUID* Protocol;
170     PVOID Interface;
171     LONG ReferenceCount;
172     BOOLEAN AddressMapped;
173 } BL_EFI_PROTOCOL, *PBL_EFI_PROTOCOL;
174 
175 NTSTATUS
EfiVmOpenProtocol(_In_ EFI_HANDLE Handle,_In_ EFI_GUID * Protocol,_Outptr_ PVOID * Interface)176 EfiVmOpenProtocol (
177     _In_ EFI_HANDLE Handle,
178     _In_ EFI_GUID* Protocol,
179     _Outptr_ PVOID* Interface
180     )
181 {
182     BOOLEAN AddressMapped;
183     PLIST_ENTRY HashList, NextEntry;
184     PHYSICAL_ADDRESS InterfaceAddress, TranslatedAddress;
185     NTSTATUS Status;
186     BL_HASH_ENTRY HashEntry;
187     PBL_HASH_VALUE HashValue;
188     PBL_EFI_PROTOCOL EfiProtocol;
189     BL_ARCH_MODE OldMode;
190     EFI_STATUS EfiStatus;
191     PVOID InterfaceVa;
192 
193     /* Initialize failure paths */
194     AddressMapped = FALSE;
195     HashList = NULL;
196     InterfaceAddress.QuadPart = 0;
197 
198     /* Have we initialized the protocol table yet? */
199     if (!EfiProtHashTableInitialized)
200     {
201         /* Nope -- create the hash table */
202         Status = BlHtCreate(0, NULL, NULL, &EfiProtHashTableId);
203         if (!NT_SUCCESS(Status))
204         {
205             return Status;
206         }
207 
208         /* Remember for next time */
209         EfiProtHashTableInitialized = TRUE;
210     }
211 
212     /* Check if we already have a list of protocols for this handle */
213     HashEntry.Flags = BL_HT_VALUE_IS_INLINE;
214     HashEntry.Size = sizeof(Handle);
215     HashEntry.Value = Handle;
216     Status = BlHtLookup(EfiProtHashTableId, &HashEntry, &HashValue);
217     if (NT_SUCCESS(Status))
218     {
219         /* We do -- the hash value is the list itself */
220         HashList = (PLIST_ENTRY)HashValue->Data;
221         NextEntry = HashList->Flink;
222 
223         /* Iterate over it */
224         while (NextEntry != HashList)
225         {
226             /* Get each protocol in the list, checking for a match */
227             EfiProtocol = CONTAINING_RECORD(NextEntry,
228                                             BL_EFI_PROTOCOL,
229                                             ListEntry);
230             if (EfiProtocol->Protocol == Protocol)
231             {
232                 /* Match found -- add a reference and return it */
233                 EfiProtocol->ReferenceCount++;
234                 *Interface = EfiProtocol->Interface;
235                 return STATUS_SUCCESS;
236             }
237 
238             /* Try the next entry */
239             NextEntry = NextEntry->Flink;
240         }
241     }
242 
243     /* Switch to real mode for firmware call */
244     OldMode = CurrentExecutionContext->Mode;
245     if (OldMode != BlRealMode)
246     {
247         BlpArchSwitchContext(BlRealMode);
248     }
249 
250     /* Check if this is EFI 1.02 */
251     if (EfiST->Hdr.Revision == EFI_1_02_SYSTEM_TABLE_REVISION)
252     {
253         /* Use the old call */
254         EfiStatus = EfiBS->HandleProtocol(Handle,
255                                           Protocol,
256                                           (PVOID*)&InterfaceAddress);
257     }
258     else
259     {
260         /* Use the EFI 2.00 API instead */
261         EfiStatus = EfiBS->OpenProtocol(Handle,
262                                         Protocol,
263                                         (PVOID*)&InterfaceAddress,
264                                         EfiImageHandle,
265                                         NULL,
266                                         EFI_OPEN_PROTOCOL_GET_PROTOCOL);
267     }
268 
269     /* Switch back to protected mode if needed */
270     if (OldMode != BlRealMode)
271     {
272         BlpArchSwitchContext(OldMode);
273     }
274 
275     /* Check the result, and bail out on failure */
276     Status = EfiGetNtStatusCode(EfiStatus);
277     if (!NT_SUCCESS(Status))
278     {
279         return Status;
280     }
281 
282     /* Check what address the interface lives at, and translate it */
283     InterfaceVa = PhysicalAddressToPtr(InterfaceAddress);
284     if (BlMmTranslateVirtualAddress(InterfaceVa, &TranslatedAddress))
285     {
286         /* We expect firmware to be 1:1 mapped, fail if not */
287         if (InterfaceAddress.QuadPart != TranslatedAddress.QuadPart)
288         {
289             return STATUS_NOT_SUPPORTED;
290         }
291     }
292     else
293     {
294         /* Create a virtual (1:1) mapping for the interface */
295         Status = BlMmMapPhysicalAddressEx(&InterfaceVa,
296                                           BlMemoryFixed,
297                                           PAGE_SIZE,
298                                           InterfaceAddress);
299         if (!NT_SUCCESS(Status))
300         {
301             return Status;
302         }
303 
304         /* Remember for cleanup */
305         AddressMapped = TRUE;
306     }
307 
308     /* The caller now has the interface */
309     *Interface = InterfaceVa;
310 
311     /* Did we already have some protocols on this handle? */
312     if (!HashList)
313     {
314         /* Nope, this is the first time -- so allocate the list */
315         HashList = BlMmAllocateHeap(sizeof(*HashList));
316         if (!HashList)
317         {
318             Status = STATUS_NO_MEMORY;
319             goto Quickie;
320         }
321 
322         /* Initialize it */
323         InitializeListHead(HashList);
324 
325         /* And then store it in the hash table for this handle */
326         Status = BlHtStore(EfiProtHashTableId,
327                            &HashEntry,
328                            HashList,
329                            sizeof(*HashList));
330         if (!NT_SUCCESS(Status))
331         {
332             BlMmFreeHeap(HashList);
333             goto Quickie;
334         }
335     }
336 
337     /* Finally, allocate a protocol tracker structure */
338     EfiProtocol = BlMmAllocateHeap(sizeof(*EfiProtocol));
339     if (!EfiProtocol)
340     {
341         Status = STATUS_NO_MEMORY;
342         goto Quickie;
343     }
344 
345     /* And store this information in case the protocol is needed again */
346     EfiProtocol->Protocol = Protocol;
347     EfiProtocol->Interface = *Interface;
348     EfiProtocol->ReferenceCount = 1;
349     EfiProtocol->AddressMapped = AddressMapped;
350     InsertTailList(HashList, &EfiProtocol->ListEntry);
351 
352     /* Passthru to success case */
353     AddressMapped = FALSE;
354 
355 Quickie:
356     /* Failure path -- did we map anything ?*/
357     if (AddressMapped)
358     {
359         /* Get rid of it */
360         BlMmUnmapVirtualAddressEx(InterfaceVa, PAGE_SIZE);
361         *Interface = NULL;
362     }
363 
364     /* Return the failure */
365     return Status;
366 }
367 
368 NTSTATUS
EfiOpenProtocol(_In_ EFI_HANDLE Handle,_In_ EFI_GUID * Protocol,_Outptr_ PVOID * Interface)369 EfiOpenProtocol (
370     _In_ EFI_HANDLE Handle,
371     _In_ EFI_GUID *Protocol,
372     _Outptr_ PVOID* Interface
373     )
374 {
375     EFI_STATUS EfiStatus;
376     NTSTATUS Status;
377     BL_ARCH_MODE OldMode;
378 
379     /* Are we using virtual memory/ */
380     if (MmTranslationType != BlNone)
381     {
382         /* We need complex tracking to make this work */
383         Status = EfiVmOpenProtocol(Handle, Protocol, Interface);
384     }
385     else
386     {
387         /* Are we in protected mode? */
388         OldMode = CurrentExecutionContext->Mode;
389         if (OldMode != BlRealMode)
390         {
391             /* Switch to real mode */
392             BlpArchSwitchContext(BlRealMode);
393         }
394 
395         /* Are we on legacy 1.02? */
396         if (EfiST->FirmwareRevision == EFI_1_02_SYSTEM_TABLE_REVISION)
397         {
398             /* Make the legacy call */
399             EfiStatus = EfiBS->HandleProtocol(Handle, Protocol, Interface);
400         }
401         else
402         {
403             /* Use the UEFI version */
404             EfiStatus = EfiBS->OpenProtocol(Handle,
405                                             Protocol,
406                                             Interface,
407                                             EfiImageHandle,
408                                             NULL,
409                                             EFI_OPEN_PROTOCOL_GET_PROTOCOL);
410 
411             /* Switch back to protected mode if we came from there */
412             if (OldMode != BlRealMode)
413             {
414                 BlpArchSwitchContext(OldMode);
415             }
416         }
417 
418         /* Convert the error to an NTSTATUS */
419         Status = EfiGetNtStatusCode(EfiStatus);
420     }
421 
422     /* Clear the interface on failure, and return the status */
423     if (!NT_SUCCESS(Status))
424     {
425         *Interface = NULL;
426     }
427 
428     return Status;
429 }
430 
431 NTSTATUS
EfiVmpCloseProtocol(_In_ EFI_HANDLE Handle,_In_ EFI_GUID * Protocol)432 EfiVmpCloseProtocol (
433     _In_ EFI_HANDLE Handle,
434     _In_ EFI_GUID* Protocol
435     )
436 {
437     EFI_STATUS EfiStatus;
438     BL_ARCH_MODE OldMode;
439 
440     /* Are we in protected mode? */
441     OldMode = CurrentExecutionContext->Mode;
442     if (OldMode != BlRealMode)
443     {
444         /* Switch to real mode */
445         BlpArchSwitchContext(BlRealMode);
446     }
447 
448     /* Are we on legacy 1.02? */
449     if (EfiST->FirmwareRevision == EFI_1_02_SYSTEM_TABLE_REVISION)
450     {
451         /* Nothing to close */
452         EfiStatus = EFI_SUCCESS;
453     }
454     else
455     {
456         /* Use the UEFI version */
457         EfiStatus = EfiBS->CloseProtocol(Handle,
458                                          Protocol,
459                                          EfiImageHandle,
460                                          NULL);
461 
462         /* Normalize not found as success */
463         if (EfiStatus == EFI_NOT_FOUND)
464         {
465             EfiStatus = EFI_SUCCESS;
466         }
467     }
468 
469     /* Switch back to protected mode if we came from there */
470     if (OldMode != BlRealMode)
471     {
472         BlpArchSwitchContext(OldMode);
473     }
474 
475     /* Convert to NT status */
476     return EfiGetNtStatusCode(EfiStatus);
477 }
478 
479 NTSTATUS
EfiVmpFreeInterfaceEntry(_In_ EFI_HANDLE Handle,_In_ PBL_EFI_PROTOCOL EfiProtocol)480 EfiVmpFreeInterfaceEntry (
481     _In_ EFI_HANDLE Handle,
482     _In_ PBL_EFI_PROTOCOL EfiProtocol
483     )
484 {
485     NTSTATUS Status;
486     BL_HASH_ENTRY HashEntry;
487 
488     /* Assume success */
489     Status = STATUS_SUCCESS;
490 
491     /* Is this the last protocol on this handle? */
492     if (IsListEmpty(&EfiProtocol->ListEntry))
493     {
494         /* Delete the hash table entry for this handle */
495         HashEntry.Value = Handle;
496         HashEntry.Size = sizeof(Handle);
497         HashEntry.Flags = BL_HT_VALUE_IS_INLINE;
498         Status = BlHtDelete(EfiProtHashTableId, &HashEntry);
499 
500         /* This will free the list head itself */
501         BlMmFreeHeap(EfiProtocol->ListEntry.Flink);
502     }
503     else
504     {
505         /* Simply remove this entry */
506         RemoveEntryList(&EfiProtocol->ListEntry);
507     }
508 
509     /* Had we virtually mapped this protocol? */
510     if (EfiProtocol->AddressMapped)
511     {
512         /* Unmap it */
513         BlMmUnmapVirtualAddressEx(EfiProtocol->Interface, PAGE_SIZE);
514     }
515 
516     /* Free the protocol entry, and return */
517     BlMmFreeHeap(EfiProtocol);
518     return Status;
519 }
520 
521 NTSTATUS
EfiVmCloseProtocol(_In_ EFI_HANDLE Handle,_In_ EFI_GUID * Protocol)522 EfiVmCloseProtocol (
523     _In_ EFI_HANDLE Handle,
524     _In_ EFI_GUID* Protocol
525     )
526 {
527     BL_HASH_ENTRY HashEntry;
528     PLIST_ENTRY ListHead, NextEntry;
529     NTSTATUS Status, CloseStatus;
530     PBL_HASH_VALUE HashValue;
531     PBL_EFI_PROTOCOL EfiProtocol;
532 
533     /* Lookup the list entry for this handle */
534     HashEntry.Size = sizeof(Handle);
535     HashEntry.Flags = BL_HT_VALUE_IS_INLINE;
536     HashEntry.Value = Handle;
537     Status = BlHtLookup(EfiProtHashTableId, &HashEntry, &HashValue);
538     if (!NT_SUCCESS(Status))
539     {
540         /* This handle was never used for any protocols  */
541         return STATUS_INVALID_PARAMETER;
542     }
543 
544     /* Iterate through the list of opened protocols */
545     ListHead = (PLIST_ENTRY)HashValue->Data;
546     NextEntry = ListHead->Flink;
547     while (NextEntry != ListHead)
548     {
549         /* Get this protocol entry and check for a match */
550         EfiProtocol = CONTAINING_RECORD(NextEntry, BL_EFI_PROTOCOL, ListEntry);
551         if (EfiProtocol->Protocol == Protocol)
552         {
553             /* Drop a reference -- was it the last one? */
554             if (EfiProtocol->ReferenceCount-- == 1)
555             {
556                 /* Yep -- free this entry */
557                 Status = EfiVmpFreeInterfaceEntry(Handle, EfiProtocol);
558 
559                 /* Call firmware to close the protocol */
560                 CloseStatus = EfiVmpCloseProtocol(Handle, Protocol);
561                 if (!NT_SUCCESS(CloseStatus))
562                 {
563                     /* Override free status if close was a failure */
564                     Status = CloseStatus;
565                 }
566 
567                 /* Return final status */
568                 return Status;
569             }
570         }
571 
572         /* Next entry */
573         NextEntry = NextEntry->Flink;
574     }
575 
576     /* This protocol was never opened */
577     return STATUS_INVALID_PARAMETER;
578 }
579 
580 NTSTATUS
EfiCloseProtocol(_In_ EFI_HANDLE Handle,_In_ EFI_GUID * Protocol)581 EfiCloseProtocol (
582     _In_ EFI_HANDLE Handle,
583     _In_ EFI_GUID *Protocol
584     )
585 {
586     EFI_STATUS EfiStatus;
587     NTSTATUS Status;
588     BL_ARCH_MODE OldMode;
589 
590     /* Are we using virtual memory/ */
591     if (MmTranslationType != BlNone)
592     {
593         /* We need complex tracking to make this work */
594         Status = EfiVmCloseProtocol(Handle, Protocol);
595     }
596     else
597     {
598         /* Are we on legacy 1.02? */
599         if (EfiST->FirmwareRevision == EFI_1_02_SYSTEM_TABLE_REVISION)
600         {
601             /* Nothing to close */
602             EfiStatus = EFI_SUCCESS;
603         }
604         else
605         {
606             /* Are we in protected mode? */
607             OldMode = CurrentExecutionContext->Mode;
608             if (OldMode != BlRealMode)
609             {
610                 /* Switch to real mode */
611                 BlpArchSwitchContext(BlRealMode);
612             }
613 
614             /* Use the UEFI version */
615             EfiStatus = EfiBS->CloseProtocol(Handle, Protocol, EfiImageHandle, NULL);
616 
617             /* Switch back to protected mode if we came from there */
618             if (OldMode != BlRealMode)
619             {
620                 BlpArchSwitchContext(OldMode);
621             }
622 
623             /* Normalize not found as success */
624             if (EfiStatus == EFI_NOT_FOUND)
625             {
626                 EfiStatus = EFI_SUCCESS;
627             }
628         }
629 
630         /* Convert the error to an NTSTATUS */
631         Status = EfiGetNtStatusCode(EfiStatus);
632     }
633 
634     /* All done */
635     return Status;
636 }
637 
638 NTSTATUS
EfiGetVariable(_In_ PWCHAR VariableName,_In_ EFI_GUID * VendorGuid,_Out_opt_ PULONG Attributes,_Inout_ PULONG DataSize,_Out_ PVOID Data)639 EfiGetVariable (
640     _In_ PWCHAR VariableName,
641     _In_ EFI_GUID* VendorGuid,
642     _Out_opt_ PULONG Attributes,
643     _Inout_ PULONG DataSize,
644     _Out_ PVOID Data
645     )
646 {
647     EFI_STATUS EfiStatus;
648     NTSTATUS Status;
649     BL_ARCH_MODE OldMode;
650     ULONG LocalAttributes;
651 
652     /* Are we in protected mode? */
653     OldMode = CurrentExecutionContext->Mode;
654     if (OldMode != BlRealMode)
655     {
656         /* FIXME: Not yet implemented */
657         EfiPrintf(L"getvar vm path\r\n");
658         EfiStall(10000000);
659         return STATUS_NOT_IMPLEMENTED;
660     }
661 
662     /* Call the runtime API */
663     EfiStatus = EfiRT->GetVariable(VariableName,
664                                    VendorGuid,
665                                    (UINT32*)&LocalAttributes,
666                                    (UINTN*)DataSize,
667                                    Data);
668 
669     /* Switch back to protected mode if we came from there */
670     if (OldMode != BlRealMode)
671     {
672         BlpArchSwitchContext(OldMode);
673     }
674 
675     /* Return attributes back to the caller if asked to */
676     if (Attributes)
677     {
678         *Attributes = LocalAttributes;
679     }
680 
681     /* Convert the error to an NTSTATUS and return it */
682     Status = EfiGetNtStatusCode(EfiStatus);
683     return Status;
684 }
685 
686 NTSTATUS
BlpSecureBootEFIIsEnabled(VOID)687 BlpSecureBootEFIIsEnabled (
688     VOID
689     )
690 {
691     NTSTATUS Status;
692     BOOLEAN SetupMode, SecureBoot;
693     ULONG DataSize;
694 
695     /* Assume setup mode enabled, and no secure boot */
696     SecureBoot = FALSE;
697     SetupMode = TRUE;
698 
699     /* Get the SetupMode variable */
700     DataSize = sizeof(SetupMode);
701     Status = EfiGetVariable(L"SetupMode",
702                             &EfiGlobalVariable,
703                             NULL,
704                             &DataSize,
705                             &SetupMode);
706     if (NT_SUCCESS(Status))
707     {
708         /* If it worked, get the SecureBoot variable */
709         DataSize = sizeof(SecureBoot);
710         Status = EfiGetVariable(L"SecureBoot",
711                                 &EfiGlobalVariable,
712                                 NULL,
713                                 &DataSize,
714                                 &SecureBoot);
715         if (NT_SUCCESS(Status))
716         {
717             /* In setup mode or without secureboot turned on, return failure */
718             if ((SecureBoot != TRUE) || (SetupMode))
719             {
720                 Status = STATUS_INVALID_SIGNATURE;
721             }
722 
723             // BlpSbdiStateFlags |= 8u;
724         }
725     }
726 
727     /* Return secureboot status */
728     return Status;
729 }
730 
731 NTSTATUS
BlSecureBootIsEnabled(_Out_ PBOOLEAN SecureBootEnabled)732 BlSecureBootIsEnabled (
733     _Out_ PBOOLEAN SecureBootEnabled
734     )
735 {
736     NTSTATUS Status;
737 
738     /* Have we checked before ? */
739     if (!BlpFirmwareChecked)
740     {
741         /* First time checking */
742         Status = BlpSecureBootEFIIsEnabled();
743         if NT_SUCCESS(Status)
744         {
745             /* Yep, it's on */
746             BlpFirmwareEnabled = TRUE;
747         }
748 
749         /* Don't check again */
750         BlpFirmwareChecked = TRUE;
751     }
752 
753     /* Return the firmware result */
754     *SecureBootEnabled = BlpFirmwareEnabled;
755     return STATUS_SUCCESS;
756 }
757 
758 NTSTATUS
BlSecureBootCheckForFactoryReset(VOID)759 BlSecureBootCheckForFactoryReset (
760     VOID
761     )
762 {
763     BOOLEAN SecureBootEnabled;
764     NTSTATUS Status;
765     ULONG DataSize;
766 
767     /* Initialize locals */
768     DataSize = 0;
769     SecureBootEnabled = FALSE;
770 
771     /* Check if secureboot is enabled */
772     Status = BlSecureBootIsEnabled(&SecureBootEnabled);
773     if (!(NT_SUCCESS(Status)) || !(SecureBootEnabled))
774     {
775         /* It's not. Check if there's a revocation list */
776         Status = EfiGetVariable(L"RevocationList",
777                                 &BlpEfiSecureBootPrivateNamespace,
778                                 NULL,
779                                 &DataSize,
780                                 NULL);
781         if ((NT_SUCCESS(Status)) || (Status == STATUS_BUFFER_TOO_SMALL))
782         {
783             /* We don't support this yet */
784             EfiPrintf(L"Not yet supported\r\n");
785             Status = STATUS_NOT_IMPLEMENTED;
786         }
787     }
788 
789     /* Return back to the caller */
790     return Status;
791 }
792 
793 NTSTATUS
EfiConInReset(VOID)794 EfiConInReset (
795     VOID
796     )
797 {
798     BL_ARCH_MODE OldMode;
799     EFI_STATUS EfiStatus;
800 
801     /* Are we in protected mode? */
802     OldMode = CurrentExecutionContext->Mode;
803     if (OldMode != BlRealMode)
804     {
805         /* FIXME: Not yet implemented */
806         EfiPrintf(L"coninreset vm path\r\n");
807         EfiStall(10000000);
808         return STATUS_NOT_IMPLEMENTED;
809     }
810 
811     /* Make the EFI call */
812     EfiStatus = EfiConIn->Reset(EfiConIn, FALSE);
813 
814     /* Switch back to protected mode if we came from there */
815     if (OldMode != BlRealMode)
816     {
817         BlpArchSwitchContext(OldMode);
818     }
819 
820     /* Convert the error to an NTSTATUS */
821     return EfiGetNtStatusCode(EfiStatus);
822 }
823 
824 NTSTATUS
EfiConInExReset(VOID)825 EfiConInExReset (
826     VOID
827     )
828 {
829     BL_ARCH_MODE OldMode;
830     EFI_STATUS EfiStatus;
831 
832     /* Are we in protected mode? */
833     OldMode = CurrentExecutionContext->Mode;
834     if (OldMode != BlRealMode)
835     {
836         /* FIXME: Not yet implemented */
837         EfiPrintf(L"conreset vm path\r\n");
838         EfiStall(10000000);
839         return STATUS_NOT_IMPLEMENTED;
840     }
841 
842     /* Make the EFI call */
843     EfiStatus = EfiConInEx->Reset(EfiConInEx, FALSE);
844 
845     /* Switch back to protected mode if we came from there */
846     if (OldMode != BlRealMode)
847     {
848         BlpArchSwitchContext(OldMode);
849     }
850 
851     /* Convert the error to an NTSTATUS */
852     return EfiGetNtStatusCode(EfiStatus);
853 }
854 
855 NTSTATUS
EfiConInExSetState(_In_ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL * ConInEx,_In_ EFI_KEY_TOGGLE_STATE * KeyToggleState)856 EfiConInExSetState (
857     _In_ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *ConInEx,
858     _In_ EFI_KEY_TOGGLE_STATE* KeyToggleState
859     )
860 {
861     BL_ARCH_MODE OldMode;
862     EFI_STATUS EfiStatus;
863     PHYSICAL_ADDRESS ConInExPhys, KeyTogglePhys;
864 
865     /* Are we in protected mode? */
866     OldMode = CurrentExecutionContext->Mode;
867     if (OldMode != BlRealMode)
868     {
869         /* Translate pointers from virtual to physical */
870         BlMmTranslateVirtualAddress(ConInEx, &ConInExPhys);
871         ConInEx = (EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL*)PhysicalAddressToPtr(ConInExPhys);
872         BlMmTranslateVirtualAddress(KeyToggleState, &KeyTogglePhys);
873         KeyToggleState = (EFI_KEY_TOGGLE_STATE*)PhysicalAddressToPtr(KeyTogglePhys);
874 
875         /* Switch to real mode */
876         BlpArchSwitchContext(BlRealMode);
877     }
878 
879     /* Make the EFI call */
880     EfiStatus = ConInEx->SetState(ConInEx, KeyToggleState);
881 
882     /* Switch back to protected mode if we came from there */
883     if (OldMode != BlRealMode)
884     {
885         BlpArchSwitchContext(OldMode);
886     }
887 
888     /* Convert the error to an NTSTATUS */
889     return EfiGetNtStatusCode(EfiStatus);
890 }
891 
892 NTSTATUS
EfiSetWatchdogTimer(VOID)893 EfiSetWatchdogTimer (
894     VOID
895     )
896 {
897     BL_ARCH_MODE OldMode;
898     EFI_STATUS EfiStatus;
899 
900     /* Are we in protected mode? */
901     OldMode = CurrentExecutionContext->Mode;
902     if (OldMode != BlRealMode)
903     {
904         /* Switch to real mode */
905         BlpArchSwitchContext(BlRealMode);
906     }
907 
908     /* Make the EFI call */
909     EfiStatus = EfiBS->SetWatchdogTimer(0, 0, 0, NULL);
910 
911     /* Switch back to protected mode if we came from there */
912     if (OldMode != BlRealMode)
913     {
914         BlpArchSwitchContext(OldMode);
915     }
916 
917     /* Convert the error to an NTSTATUS */
918     return EfiGetNtStatusCode(EfiStatus);
919 }
920 
921 NTSTATUS
EfiGetMemoryMap(_Out_ UINTN * MemoryMapSize,_Inout_ EFI_MEMORY_DESCRIPTOR * MemoryMap,_Out_ UINTN * MapKey,_Out_ UINTN * DescriptorSize,_Out_ UINTN * DescriptorVersion)922 EfiGetMemoryMap (
923     _Out_ UINTN* MemoryMapSize,
924     _Inout_ EFI_MEMORY_DESCRIPTOR *MemoryMap,
925     _Out_ UINTN* MapKey,
926     _Out_ UINTN* DescriptorSize,
927     _Out_ UINTN* DescriptorVersion
928     )
929 {
930     BL_ARCH_MODE OldMode;
931     EFI_STATUS EfiStatus;
932     PHYSICAL_ADDRESS MemoryMapSizePhysical, MemoryMapPhysical, MapKeyPhysical;
933     PHYSICAL_ADDRESS DescriptorSizePhysical, DescriptorVersionPhysical;
934 
935     /* Are we in protected mode? */
936     OldMode = CurrentExecutionContext->Mode;
937     if (OldMode != BlRealMode)
938     {
939         /* Convert all of the addresses to physical */
940         BlMmTranslateVirtualAddress(MemoryMapSize, &MemoryMapSizePhysical);
941         MemoryMapSize = (UINTN*)PhysicalAddressToPtr(MemoryMapSizePhysical);
942         BlMmTranslateVirtualAddress(MemoryMap, &MemoryMapPhysical);
943         MemoryMap = (EFI_MEMORY_DESCRIPTOR*)PhysicalAddressToPtr(MemoryMapPhysical);
944         BlMmTranslateVirtualAddress(MapKey, &MapKeyPhysical);
945         MapKey = (UINTN*)PhysicalAddressToPtr(MapKeyPhysical);
946         BlMmTranslateVirtualAddress(DescriptorSize, &DescriptorSizePhysical);
947         DescriptorSize = (UINTN*)PhysicalAddressToPtr(DescriptorSizePhysical);
948         BlMmTranslateVirtualAddress(DescriptorVersion, &DescriptorVersionPhysical);
949         DescriptorVersion = (UINTN*)PhysicalAddressToPtr(DescriptorVersionPhysical);
950 
951         /* Switch to real mode */
952         BlpArchSwitchContext(BlRealMode);
953     }
954 
955     /* Make the EFI call */
956     EfiStatus = EfiBS->GetMemoryMap(MemoryMapSize,
957                                     MemoryMap,
958                                     MapKey,
959                                     DescriptorSize,
960                                     DescriptorVersion);
961 
962     /* Switch back to protected mode if we came from there */
963     if (OldMode != BlRealMode)
964     {
965         BlpArchSwitchContext(OldMode);
966     }
967 
968     /* Convert the error to an NTSTATUS */
969     return EfiGetNtStatusCode(EfiStatus);
970 }
971 
972 NTSTATUS
EfiFreePages(_In_ ULONG Pages,_In_ EFI_PHYSICAL_ADDRESS PhysicalAddress)973 EfiFreePages (
974     _In_ ULONG Pages,
975     _In_ EFI_PHYSICAL_ADDRESS PhysicalAddress
976     )
977 {
978     BL_ARCH_MODE OldMode;
979     EFI_STATUS EfiStatus;
980 
981     /* Are we in protected mode? */
982     OldMode = CurrentExecutionContext->Mode;
983     if (OldMode != BlRealMode)
984     {
985         /* Switch to real mode */
986         BlpArchSwitchContext(BlRealMode);
987     }
988 
989     /* Make the EFI call */
990     EfiStatus = EfiBS->FreePages(PhysicalAddress, Pages);
991 
992     /* Switch back to protected mode if we came from there */
993     if (OldMode != BlRealMode)
994     {
995         BlpArchSwitchContext(OldMode);
996     }
997 
998     /* Convert the error to an NTSTATUS */
999     return EfiGetNtStatusCode(EfiStatus);
1000 }
1001 
1002 NTSTATUS
EfiStall(_In_ ULONG StallTime)1003 EfiStall (
1004     _In_ ULONG StallTime
1005     )
1006 {
1007     BL_ARCH_MODE OldMode;
1008     EFI_STATUS EfiStatus;
1009 
1010     /* Are we in protected mode? */
1011     OldMode = CurrentExecutionContext->Mode;
1012     if (OldMode != BlRealMode)
1013     {
1014         /* Switch to real mode */
1015         BlpArchSwitchContext(BlRealMode);
1016     }
1017 
1018     /* Make the EFI call */
1019     EfiStatus = EfiBS->Stall(StallTime);
1020 
1021     /* Switch back to protected mode if we came from there */
1022     if (OldMode != BlRealMode)
1023     {
1024         BlpArchSwitchContext(OldMode);
1025     }
1026 
1027     /* Convert the error to an NTSTATUS */
1028     return EfiGetNtStatusCode(EfiStatus);
1029 }
1030 
1031 NTSTATUS
EfiConOutQueryMode(_In_ SIMPLE_TEXT_OUTPUT_INTERFACE * TextInterface,_In_ ULONG Mode,_In_ UINTN * Columns,_In_ UINTN * Rows)1032 EfiConOutQueryMode (
1033     _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
1034     _In_ ULONG Mode,
1035     _In_ UINTN* Columns,
1036     _In_ UINTN* Rows
1037     )
1038 {
1039     BL_ARCH_MODE OldMode;
1040     EFI_STATUS EfiStatus;
1041 
1042     /* Are we in protected mode? */
1043     OldMode = CurrentExecutionContext->Mode;
1044     if (OldMode != BlRealMode)
1045     {
1046         /* FIXME: Not yet implemented */
1047         EfiPrintf(L"conqmode vm path\r\n");
1048         EfiStall(10000000);
1049         return STATUS_NOT_IMPLEMENTED;
1050     }
1051 
1052     /* Make the EFI call */
1053     EfiStatus = TextInterface->QueryMode(TextInterface, Mode, Columns, Rows);
1054 
1055     /* Switch back to protected mode if we came from there */
1056     if (OldMode != BlRealMode)
1057     {
1058         BlpArchSwitchContext(OldMode);
1059     }
1060 
1061     /* Convert the error to an NTSTATUS */
1062     return EfiGetNtStatusCode(EfiStatus);
1063 }
1064 
1065 NTSTATUS
EfiConOutSetMode(_In_ SIMPLE_TEXT_OUTPUT_INTERFACE * TextInterface,_In_ ULONG Mode)1066 EfiConOutSetMode (
1067     _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
1068     _In_ ULONG Mode
1069     )
1070 {
1071     BL_ARCH_MODE OldMode;
1072     EFI_STATUS EfiStatus;
1073 
1074     /* Are we in protected mode? */
1075     OldMode = CurrentExecutionContext->Mode;
1076     if (OldMode != BlRealMode)
1077     {
1078         /* FIXME: Not yet implemented */
1079         EfiPrintf(L"setmode vm path\r\n");
1080         EfiStall(10000000);
1081         return STATUS_NOT_IMPLEMENTED;
1082     }
1083 
1084     /* Make the EFI call */
1085     EfiStatus = TextInterface->SetMode(TextInterface, Mode);
1086 
1087     /* Switch back to protected mode if we came from there */
1088     if (OldMode != BlRealMode)
1089     {
1090         BlpArchSwitchContext(OldMode);
1091     }
1092 
1093     /* Convert the error to an NTSTATUS */
1094     return EfiGetNtStatusCode(EfiStatus);
1095 }
1096 
1097 NTSTATUS
EfiConOutSetAttribute(_In_ SIMPLE_TEXT_OUTPUT_INTERFACE * TextInterface,_In_ ULONG Attribute)1098 EfiConOutSetAttribute (
1099     _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
1100     _In_ ULONG Attribute
1101     )
1102 {
1103     BL_ARCH_MODE OldMode;
1104     EFI_STATUS EfiStatus;
1105 
1106     /* Are we in protected mode? */
1107     OldMode = CurrentExecutionContext->Mode;
1108     if (OldMode != BlRealMode)
1109     {
1110         /* FIXME: Not yet implemented */
1111         EfiPrintf(L"sattr vm path\r\n");
1112         EfiStall(10000000);
1113         return STATUS_NOT_IMPLEMENTED;
1114     }
1115 
1116     /* Make the EFI call */
1117     EfiStatus = TextInterface->SetAttribute(TextInterface, Attribute);
1118 
1119     /* Switch back to protected mode if we came from there */
1120     if (OldMode != BlRealMode)
1121     {
1122         BlpArchSwitchContext(OldMode);
1123     }
1124 
1125     /* Convert the error to an NTSTATUS */
1126     return EfiGetNtStatusCode(EfiStatus);
1127 }
1128 
1129 NTSTATUS
EfiConOutSetCursorPosition(_In_ SIMPLE_TEXT_OUTPUT_INTERFACE * TextInterface,_In_ ULONG Column,_In_ ULONG Row)1130 EfiConOutSetCursorPosition (
1131     _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
1132     _In_ ULONG Column,
1133     _In_ ULONG Row
1134     )
1135 {
1136     BL_ARCH_MODE OldMode;
1137     EFI_STATUS EfiStatus;
1138 
1139     /* Are we in protected mode? */
1140     OldMode = CurrentExecutionContext->Mode;
1141     if (OldMode != BlRealMode)
1142     {
1143         /* FIXME: Not yet implemented */
1144         EfiPrintf(L"setcursor vm path\r\n");
1145         EfiStall(10000000);
1146         return STATUS_NOT_IMPLEMENTED;
1147     }
1148 
1149     /* Make the EFI call */
1150     EfiStatus = TextInterface->SetCursorPosition(TextInterface, Column, Row);
1151 
1152     /* Switch back to protected mode if we came from there */
1153     if (OldMode != BlRealMode)
1154     {
1155         BlpArchSwitchContext(OldMode);
1156     }
1157 
1158     /* Convert the error to an NTSTATUS */
1159     return EfiGetNtStatusCode(EfiStatus);
1160 }
1161 
1162 NTSTATUS
EfiConOutEnableCursor(_In_ SIMPLE_TEXT_OUTPUT_INTERFACE * TextInterface,_In_ BOOLEAN Visible)1163 EfiConOutEnableCursor (
1164     _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
1165     _In_ BOOLEAN Visible
1166     )
1167 {
1168     BL_ARCH_MODE OldMode;
1169     EFI_STATUS EfiStatus;
1170 
1171     /* Are we in protected mode? */
1172     OldMode = CurrentExecutionContext->Mode;
1173     if (OldMode != BlRealMode)
1174     {
1175         /* FIXME: Not yet implemented */
1176         EfiPrintf(L"enablecurso vm path\r\n");
1177         EfiStall(10000000);
1178         return STATUS_NOT_IMPLEMENTED;
1179     }
1180 
1181     /* Make the EFI call */
1182     EfiStatus = TextInterface->EnableCursor(TextInterface, Visible);
1183 
1184     /* Switch back to protected mode if we came from there */
1185     if (OldMode != BlRealMode)
1186     {
1187         BlpArchSwitchContext(OldMode);
1188     }
1189 
1190     /* Convert the error to an NTSTATUS */
1191     return EfiGetNtStatusCode(EfiStatus);
1192 }
1193 
1194 NTSTATUS
EfiConOutOutputString(_In_ SIMPLE_TEXT_OUTPUT_INTERFACE * TextInterface,_In_ PWCHAR String)1195 EfiConOutOutputString (
1196     _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
1197     _In_ PWCHAR String
1198     )
1199 {
1200     BL_ARCH_MODE OldMode;
1201     EFI_STATUS EfiStatus;
1202 
1203     /* Are we in protected mode? */
1204     OldMode = CurrentExecutionContext->Mode;
1205     if (OldMode != BlRealMode)
1206     {
1207         /* FIXME: Not yet implemented */
1208         EfiPrintf(L"output string vm path\r\n");
1209         EfiStall(10000000);
1210         return STATUS_NOT_IMPLEMENTED;
1211     }
1212 
1213     /* Make the EFI call */
1214     EfiStatus = TextInterface->OutputString(TextInterface, String);
1215 
1216     /* Switch back to protected mode if we came from there */
1217     if (OldMode != BlRealMode)
1218     {
1219         BlpArchSwitchContext(OldMode);
1220     }
1221 
1222     /* Convert the error to an NTSTATUS */
1223     return EfiGetNtStatusCode(EfiStatus);
1224 }
1225 
1226 VOID
EfiConOutReadCurrentMode(_In_ SIMPLE_TEXT_OUTPUT_INTERFACE * TextInterface,_Out_ EFI_SIMPLE_TEXT_OUTPUT_MODE * Mode)1227 EfiConOutReadCurrentMode (
1228     _In_ SIMPLE_TEXT_OUTPUT_INTERFACE *TextInterface,
1229     _Out_ EFI_SIMPLE_TEXT_OUTPUT_MODE* Mode
1230     )
1231 {
1232     BL_ARCH_MODE OldMode;
1233 
1234     /* Are we in protected mode? */
1235     OldMode = CurrentExecutionContext->Mode;
1236     if (OldMode != BlRealMode)
1237     {
1238         /* FIXME: Not yet implemented */
1239         EfiPrintf(L"readmode vm path\r\n");
1240         EfiStall(10000000);
1241         return;
1242     }
1243 
1244     /* Make the EFI call */
1245     RtlCopyMemory(Mode, TextInterface->Mode, sizeof(*Mode));
1246 
1247     /* Switch back to protected mode if we came from there */
1248     if (OldMode != BlRealMode)
1249     {
1250         BlpArchSwitchContext(OldMode);
1251     }
1252 }
1253 
1254 VOID
EfiGopGetFrameBuffer(_In_ EFI_GRAPHICS_OUTPUT_PROTOCOL * GopInterface,_Out_ PHYSICAL_ADDRESS * FrameBuffer,_Out_ UINTN * FrameBufferSize)1255 EfiGopGetFrameBuffer (
1256     _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopInterface,
1257     _Out_ PHYSICAL_ADDRESS* FrameBuffer,
1258     _Out_ UINTN *FrameBufferSize
1259     )
1260 {
1261     BL_ARCH_MODE OldMode;
1262     PHYSICAL_ADDRESS GopInterfacePhys, FrameBufferPhys, FrameBufferSizePhys;
1263 
1264     /* Are we in protected mode? */
1265     OldMode = CurrentExecutionContext->Mode;
1266     if (OldMode != BlRealMode)
1267     {
1268         /* Translate pointer to physical */
1269         BlMmTranslateVirtualAddress(GopInterface, &GopInterfacePhys);
1270         GopInterface = PhysicalAddressToPtr(GopInterfacePhys);
1271 
1272         /* Translate pointer to physical */
1273         BlMmTranslateVirtualAddress(FrameBuffer, &FrameBufferPhys);
1274         FrameBuffer = PhysicalAddressToPtr(FrameBufferPhys);
1275 
1276         /* Translate pointer to physical */
1277         BlMmTranslateVirtualAddress(FrameBufferSize, &FrameBufferSizePhys);
1278         FrameBufferSize = PhysicalAddressToPtr(FrameBufferSizePhys);
1279 
1280         /* Switch to real mode */
1281         BlpArchSwitchContext(BlRealMode);
1282     }
1283 
1284     /* Make the EFI call */
1285     FrameBuffer->QuadPart = GopInterface->Mode->FrameBufferBase;
1286     *FrameBufferSize = GopInterface->Mode->FrameBufferSize;
1287 
1288     /* Switch back to protected mode if we came from there */
1289     if (OldMode != BlRealMode)
1290     {
1291         BlpArchSwitchContext(OldMode);
1292     }
1293 }
1294 
1295 NTSTATUS
EfiGopGetCurrentMode(_In_ EFI_GRAPHICS_OUTPUT_PROTOCOL * GopInterface,_Out_ UINTN * Mode,_Out_ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION * Information)1296 EfiGopGetCurrentMode (
1297     _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopInterface,
1298     _Out_ UINTN* Mode,
1299     _Out_ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Information
1300     )
1301 {
1302     BL_ARCH_MODE OldMode;
1303     PHYSICAL_ADDRESS GopInterfacePhys, ModePhys, InformationPhys;
1304 
1305     /* Are we in protected mode? */
1306     OldMode = CurrentExecutionContext->Mode;
1307     if (OldMode != BlRealMode)
1308     {
1309         /* Translate pointer to physical */
1310         if (!BlMmTranslateVirtualAddress(GopInterface, &GopInterfacePhys))
1311         {
1312             return STATUS_UNSUCCESSFUL;
1313         }
1314         GopInterface = PhysicalAddressToPtr(GopInterfacePhys);
1315 
1316         /* Translate pointer to physical */
1317         if (!BlMmTranslateVirtualAddress(Mode, &ModePhys))
1318         {
1319             return STATUS_UNSUCCESSFUL;
1320         }
1321         Mode = PhysicalAddressToPtr(ModePhys);
1322 
1323         /* Translate pointer to physical */
1324         if (!BlMmTranslateVirtualAddress(Information, &InformationPhys))
1325         {
1326             return STATUS_UNSUCCESSFUL;
1327         }
1328         Information = PhysicalAddressToPtr(InformationPhys);
1329 
1330         /* Switch to real mode */
1331         BlpArchSwitchContext(BlRealMode);
1332     }
1333 
1334     /* Make the EFI call */
1335     *Mode = GopInterface->Mode->Mode;
1336     RtlCopyMemory(Information, GopInterface->Mode->Info, sizeof(*Information));
1337 
1338     /* Switch back to protected mode if we came from there */
1339     if (OldMode != BlRealMode)
1340     {
1341         BlpArchSwitchContext(OldMode);
1342     }
1343 
1344     /* Return back */
1345     return STATUS_SUCCESS;
1346 }
1347 
1348 NTSTATUS
EfiGopSetMode(_In_ EFI_GRAPHICS_OUTPUT_PROTOCOL * GopInterface,_In_ ULONG Mode)1349 EfiGopSetMode (
1350     _In_ EFI_GRAPHICS_OUTPUT_PROTOCOL *GopInterface,
1351     _In_ ULONG Mode
1352     )
1353 {
1354     BL_ARCH_MODE OldMode;
1355     EFI_STATUS EfiStatus;
1356     BOOLEAN ModeChanged;
1357     NTSTATUS Status;
1358 
1359     /* Are we in protected mode? */
1360     OldMode = CurrentExecutionContext->Mode;
1361     if (OldMode != BlRealMode)
1362     {
1363         /* FIXME: Not yet implemented */
1364         EfiPrintf(L"gopsmode vm path\r\n");
1365         EfiStall(10000000);
1366         return STATUS_NOT_IMPLEMENTED;
1367     }
1368 
1369     /* Make the EFI call */
1370     if (Mode == GopInterface->Mode->Mode)
1371     {
1372         EfiStatus = EFI_SUCCESS;
1373         ModeChanged = FALSE;
1374     }
1375     {
1376         EfiStatus = GopInterface->SetMode(GopInterface, Mode);
1377         ModeChanged = TRUE;
1378     }
1379 
1380     /* Switch back to protected mode if we came from there */
1381     if (OldMode != BlRealMode)
1382     {
1383         BlpArchSwitchContext(OldMode);
1384     }
1385 
1386     /* Print out to the debugger if the mode was changed */
1387     Status = EfiGetNtStatusCode(EfiStatus);
1388     if ((ModeChanged) && (NT_SUCCESS(Status)))
1389     {
1390         /* FIXME @TODO: Should be BlStatusPrint */
1391         EfiPrintf(L"Console video mode set to 0x%x\r\n", Mode);
1392     }
1393 
1394     /* Convert the error to an NTSTATUS */
1395     return Status;
1396 }
1397 
1398 NTSTATUS
EfiLocateHandleBuffer(_In_ EFI_LOCATE_SEARCH_TYPE SearchType,_In_ EFI_GUID * Protocol,_Inout_ PULONG HandleCount,_Inout_ EFI_HANDLE ** Buffer)1399 EfiLocateHandleBuffer (
1400     _In_ EFI_LOCATE_SEARCH_TYPE SearchType,
1401     _In_ EFI_GUID *Protocol,
1402     _Inout_ PULONG HandleCount,
1403     _Inout_ EFI_HANDLE** Buffer
1404     )
1405 {
1406     BL_ARCH_MODE OldMode;
1407     EFI_STATUS EfiStatus;
1408     UINTN BufferSize;
1409     PVOID InputBuffer;
1410     BOOLEAN TranslateResult;
1411     PHYSICAL_ADDRESS BufferPhys;
1412 
1413     /* Bail out if we're missing parameters */
1414     if (!(Buffer) || !(HandleCount))
1415     {
1416         return STATUS_INVALID_PARAMETER;
1417     }
1418 
1419     /* Check if a buffer was passed in*/
1420     InputBuffer = *Buffer;
1421     if (InputBuffer)
1422     {
1423         /* Then we should already have a buffer size*/
1424         BufferSize = sizeof(EFI_HANDLE) * *HandleCount;
1425     }
1426     else
1427     {
1428         /* Then no buffer size exists */
1429         BufferSize = 0;
1430     }
1431 
1432     /* Are we in protected mode? */
1433     OldMode = CurrentExecutionContext->Mode;
1434     if (OldMode != BlRealMode)
1435     {
1436         /* Translate the input buffer from virtual to physical */
1437         TranslateResult = BlMmTranslateVirtualAddress(InputBuffer, &BufferPhys);
1438         InputBuffer = TranslateResult ? PhysicalAddressToPtr(BufferPhys) : NULL;
1439 
1440         /* Switch to real mode */
1441         BlpArchSwitchContext(BlRealMode);
1442     }
1443 
1444     /* Try the first time */
1445     EfiStatus = EfiBS->LocateHandle(SearchType,
1446                                     Protocol,
1447                                     NULL,
1448                                     &BufferSize,
1449                                     InputBuffer);
1450 
1451     /* Switch back to protected mode if we came from there */
1452     if (OldMode != BlRealMode)
1453     {
1454         BlpArchSwitchContext(OldMode);
1455     }
1456 
1457     /* Check result of first search */
1458     if (EfiStatus == EFI_BUFFER_TOO_SMALL)
1459     {
1460         /* Did we have an existing buffer? */
1461         if (*Buffer)
1462         {
1463             /* Free it */
1464             BlMmFreeHeap(*Buffer);
1465         }
1466 
1467         /* Allocate a new one */
1468         InputBuffer = BlMmAllocateHeap(BufferSize);
1469         *Buffer = InputBuffer;
1470         if (!InputBuffer)
1471         {
1472             /* No space, fail */
1473             return STATUS_NO_MEMORY;
1474         }
1475 
1476         if (OldMode != BlRealMode)
1477         {
1478             /* Translate the input buffer from virtual to physical */
1479             TranslateResult = BlMmTranslateVirtualAddress(InputBuffer,
1480                                                           &BufferPhys);
1481             InputBuffer = TranslateResult ? PhysicalAddressToPtr(BufferPhys) : NULL;
1482 
1483             /* Switch to real mode */
1484             BlpArchSwitchContext(BlRealMode);
1485         }
1486 
1487         /* Try again */
1488         EfiStatus = EfiBS->LocateHandle(SearchType,
1489                                         Protocol,
1490                                         NULL,
1491                                         &BufferSize,
1492                                         InputBuffer);
1493 
1494         /* Switch back to protected mode if we came from there */
1495         if (OldMode != BlRealMode)
1496         {
1497             BlpArchSwitchContext(OldMode);
1498         }
1499     }
1500 
1501     /* Return the number of handles */
1502     *HandleCount = BufferSize / sizeof(EFI_HANDLE);
1503 
1504     /* Convert the error to an NTSTATUS */
1505     return EfiGetNtStatusCode(EfiStatus);
1506 }
1507 
1508 VOID
EfiResetSystem(_In_ EFI_RESET_TYPE ResetType)1509 EfiResetSystem (
1510     _In_ EFI_RESET_TYPE ResetType
1511     )
1512 {
1513     BL_ARCH_MODE OldMode;
1514 
1515     /* Are we in protected mode? */
1516     OldMode = CurrentExecutionContext->Mode;
1517     if (OldMode != BlRealMode)
1518     {
1519         /* FIXME: Not yet implemented */
1520         EfiPrintf(L"reset vm path\r\n");
1521         EfiStall(10000000);
1522         return;
1523     }
1524 
1525     /* Call the EFI runtime */
1526     EfiRT->ResetSystem(ResetType, EFI_SUCCESS, 0, NULL);
1527 }
1528 
1529 NTSTATUS
EfiConnectController(_In_ EFI_HANDLE ControllerHandle)1530 EfiConnectController (
1531     _In_ EFI_HANDLE ControllerHandle
1532     )
1533 {
1534     BL_ARCH_MODE OldMode;
1535     EFI_STATUS EfiStatus;
1536 
1537     /* Is this EFI 1.02? */
1538     if (EfiST->Hdr.Revision == EFI_1_02_SYSTEM_TABLE_REVISION)
1539     {
1540         /* This function didn't exist back then */
1541         return STATUS_NOT_SUPPORTED;
1542     }
1543 
1544     /* Are we in protected mode? */
1545     OldMode = CurrentExecutionContext->Mode;
1546     if (OldMode != BlRealMode)
1547     {
1548         /* FIXME: Not yet implemented */
1549         EfiPrintf(L"connectctrl vm path\r\n");
1550         EfiStall(10000000);
1551         return STATUS_NOT_IMPLEMENTED;
1552     }
1553 
1554     /* Make the EFI call */
1555     EfiStatus = EfiBS->ConnectController(ControllerHandle, NULL, NULL, TRUE);
1556 
1557     /* Switch back to protected mode if we came from there */
1558     if (OldMode != BlRealMode)
1559     {
1560         BlpArchSwitchContext(OldMode);
1561     }
1562 
1563     /* Convert the error to an NTSTATUS */
1564     return EfiGetNtStatusCode(EfiStatus);
1565 }
1566 
1567 NTSTATUS
EfiAllocatePages(_In_ ULONG Type,_In_ ULONG Pages,_Inout_ EFI_PHYSICAL_ADDRESS * Memory)1568 EfiAllocatePages (
1569     _In_ ULONG Type,
1570     _In_ ULONG Pages,
1571     _Inout_ EFI_PHYSICAL_ADDRESS* Memory
1572     )
1573 {
1574     BL_ARCH_MODE OldMode;
1575     EFI_STATUS EfiStatus;
1576     PHYSICAL_ADDRESS MemoryPhysical;
1577 
1578     /* Are we in protected mode? */
1579     OldMode = CurrentExecutionContext->Mode;
1580     if (OldMode != BlRealMode)
1581     {
1582         /* Translate output address */
1583         BlMmTranslateVirtualAddress(Memory, &MemoryPhysical);
1584         Memory = (EFI_PHYSICAL_ADDRESS*)PhysicalAddressToPtr(MemoryPhysical);
1585 
1586         /* Switch to real mode */
1587         BlpArchSwitchContext(BlRealMode);
1588     }
1589 
1590     /* Make the EFI call */
1591     EfiStatus = EfiBS->AllocatePages(Type, EfiLoaderData, Pages, Memory);
1592 
1593     /* Switch back to protected mode if we came from there */
1594     if (OldMode != BlRealMode)
1595     {
1596         BlpArchSwitchContext(OldMode);
1597     }
1598 
1599     /* Convert the error to an NTSTATUS */
1600     return EfiGetNtStatusCode(EfiStatus);
1601 }
1602 
1603 NTSTATUS
EfipGetSystemTable(_In_ EFI_GUID * TableGuid,_Out_ PPHYSICAL_ADDRESS TableAddress)1604 EfipGetSystemTable (
1605     _In_ EFI_GUID *TableGuid,
1606     _Out_ PPHYSICAL_ADDRESS TableAddress
1607     )
1608 {
1609     ULONG i;
1610     NTSTATUS Status;
1611 
1612     /* Assume failure */
1613     Status = STATUS_NOT_FOUND;
1614 
1615     /* Loop through the configuration tables */
1616     for (i = 0; i < EfiST->NumberOfTableEntries; i++)
1617     {
1618         /* Check if this one matches the one we want */
1619         if (RtlEqualMemory(&EfiST->ConfigurationTable[i].VendorGuid,
1620                            TableGuid,
1621                            sizeof(*TableGuid)))
1622         {
1623             /* Return its address */
1624             TableAddress->QuadPart = (ULONG_PTR)EfiST->ConfigurationTable[i].VendorTable;
1625             Status = STATUS_SUCCESS;
1626             break;
1627         }
1628     }
1629 
1630     /* Return the search result */
1631     return Status;
1632 }
1633 
1634 NTSTATUS
EfipGetRsdt(_Out_ PPHYSICAL_ADDRESS FoundRsdt)1635 EfipGetRsdt (
1636     _Out_ PPHYSICAL_ADDRESS FoundRsdt
1637     )
1638 {
1639     NTSTATUS Status;
1640     ULONG Length;
1641     PHYSICAL_ADDRESS RsdpAddress, Rsdt;
1642     PRSDP Rsdp;
1643 
1644     /* Assume failure */
1645     Length = 0;
1646     Rsdp = NULL;
1647 
1648     /* Check if we already know it */
1649     if (EfiRsdt.QuadPart)
1650     {
1651         /* Return it */
1652         *FoundRsdt = EfiRsdt;
1653         return STATUS_SUCCESS;
1654     }
1655 
1656     /* Otherwise, look for the ACPI 2.0 RSDP (XSDT really) */
1657     Status = EfipGetSystemTable(&EfiRootAcpiTableGuid, &RsdpAddress);
1658     if (!NT_SUCCESS(Status))
1659     {
1660         /* Didn't fint it, look for the ACPI 1.0 RSDP (RSDT really) */
1661         Status = EfipGetSystemTable(&EfiRootAcpiTable10Guid, &RsdpAddress);
1662         if (!NT_SUCCESS(Status))
1663         {
1664             return Status;
1665         }
1666     }
1667 
1668     /* Map it */
1669     Length = sizeof(*Rsdp);
1670     Status = BlMmMapPhysicalAddressEx((PVOID*)&Rsdp,
1671                                       0,
1672                                       Length,
1673                                       RsdpAddress);
1674     if (NT_SUCCESS(Status))
1675     {
1676         /* Check the revision (anything >= 2.0 is XSDT) */
1677         if (Rsdp->Revision)
1678         {
1679             /* Check if the table is bigger than just its header */
1680             if (Rsdp->Length > Length)
1681             {
1682                 /* Capture the real length */
1683                 Length = Rsdp->Length;
1684 
1685                 /* Unmap our header mapping */
1686                 BlMmUnmapVirtualAddressEx(Rsdp, sizeof(*Rsdp));
1687 
1688                 /* And map the whole thing now */
1689                 Status = BlMmMapPhysicalAddressEx((PVOID*)&Rsdp,
1690                                                   0,
1691                                                   Length,
1692                                                   RsdpAddress);
1693                 if (!NT_SUCCESS(Status))
1694                 {
1695                     return Status;
1696                 }
1697             }
1698 
1699             /* Read the XSDT address from the table*/
1700             Rsdt = Rsdp->XsdtAddress;
1701         }
1702         else
1703         {
1704             /* ACPI 1.0 so just read the RSDT */
1705             Rsdt.QuadPart = Rsdp->RsdtAddress;
1706         }
1707 
1708         /* Save it for later */
1709         EfiRsdt = Rsdt;
1710 
1711         /* And return it back */
1712         *FoundRsdt = Rsdt;
1713     }
1714 
1715     /* Check if we had mapped the RSDP */
1716     if (Rsdp)
1717     {
1718         /* Unmap it */
1719         BlMmUnmapVirtualAddressEx(Rsdp, Length);
1720     }
1721 
1722     /* Return search result back to caller */
1723     return Status;
1724 }
1725 
1726 BL_MEMORY_ATTR
MmFwpGetOsAttributeType(_In_ ULONGLONG Attribute)1727 MmFwpGetOsAttributeType (
1728     _In_ ULONGLONG Attribute
1729     )
1730 {
1731     BL_MEMORY_ATTR OsAttribute = 0;
1732 
1733     if (Attribute & EFI_MEMORY_UC)
1734     {
1735         OsAttribute = BlMemoryUncached;
1736     }
1737 
1738     if (Attribute & EFI_MEMORY_WC)
1739     {
1740         OsAttribute |= BlMemoryWriteCombined;
1741     }
1742 
1743     if (Attribute & EFI_MEMORY_WT)
1744     {
1745         OsAttribute |= BlMemoryWriteThrough;
1746     }
1747 
1748     if (Attribute & EFI_MEMORY_WB)
1749     {
1750         OsAttribute |= BlMemoryWriteBack;
1751     }
1752 
1753     if (Attribute & EFI_MEMORY_UCE)
1754     {
1755         OsAttribute |= BlMemoryUncachedExported;
1756     }
1757 
1758     if (Attribute & EFI_MEMORY_WP)
1759     {
1760         OsAttribute |= BlMemoryWriteProtected;
1761     }
1762 
1763     if (Attribute & EFI_MEMORY_RP)
1764     {
1765         OsAttribute |= BlMemoryReadProtected;
1766     }
1767 
1768     if (Attribute & EFI_MEMORY_XP)
1769     {
1770         OsAttribute |= BlMemoryExecuteProtected;
1771     }
1772 
1773     if (Attribute & EFI_MEMORY_RUNTIME)
1774     {
1775         OsAttribute |= BlMemoryRuntime;
1776     }
1777 
1778     return OsAttribute;
1779 }
1780 
1781 BL_MEMORY_TYPE
MmFwpGetOsMemoryType(_In_ EFI_MEMORY_TYPE MemoryType)1782 MmFwpGetOsMemoryType (
1783     _In_ EFI_MEMORY_TYPE MemoryType
1784     )
1785 {
1786     BL_MEMORY_TYPE OsType;
1787 
1788     switch (MemoryType)
1789     {
1790         case EfiLoaderCode:
1791         case EfiLoaderData:
1792             OsType = BlLoaderMemory;
1793             break;
1794 
1795         case EfiBootServicesCode:
1796         case EfiBootServicesData:
1797             OsType = BlEfiBootMemory;
1798             break;
1799 
1800         case EfiRuntimeServicesCode:
1801             OsType = BlEfiRuntimeCodeMemory;
1802             break;
1803 
1804         case EfiRuntimeServicesData:
1805             OsType = BlEfiRuntimeDataMemory;
1806             break;
1807 
1808         case EfiConventionalMemory:
1809             OsType = BlConventionalMemory;
1810             break;
1811 
1812         case EfiUnusableMemory:
1813             OsType = BlUnusableMemory;
1814             break;
1815 
1816         case EfiACPIReclaimMemory:
1817             OsType = BlAcpiReclaimMemory;
1818             break;
1819 
1820         case EfiACPIMemoryNVS:
1821             OsType = BlAcpiNvsMemory;
1822             break;
1823 
1824         case EfiMemoryMappedIO:
1825             OsType = BlDeviceIoMemory;
1826             break;
1827 
1828         case EfiMemoryMappedIOPortSpace:
1829             OsType = BlDevicePortMemory;
1830             break;
1831 
1832         case EfiPalCode:
1833             OsType = BlPalMemory;
1834             break;
1835 
1836         default:
1837             OsType = BlReservedMemory;
1838             break;
1839     }
1840 
1841     return OsType;
1842 }
1843 
1844 NTSTATUS
MmFwGetMemoryMap(_Out_ PBL_MEMORY_DESCRIPTOR_LIST MemoryMap,_In_ ULONG Flags)1845 MmFwGetMemoryMap (
1846     _Out_ PBL_MEMORY_DESCRIPTOR_LIST MemoryMap,
1847     _In_ ULONG Flags
1848     )
1849 {
1850     BL_LIBRARY_PARAMETERS LibraryParameters = BlpLibraryParameters;
1851     BOOLEAN UseEfiBuffer, HaveRamDisk;
1852     NTSTATUS Status;
1853     ULONGLONG Pages, StartPage, EndPage, EfiBufferPage;
1854     UINTN EfiMemoryMapSize, MapKey, DescriptorSize, DescriptorVersion;
1855     EFI_PHYSICAL_ADDRESS EfiBuffer = 0;
1856     EFI_MEMORY_DESCRIPTOR* EfiMemoryMap;
1857     EFI_STATUS EfiStatus;
1858     BL_ARCH_MODE OldMode;
1859     EFI_MEMORY_DESCRIPTOR EfiDescriptor;
1860     BL_MEMORY_TYPE MemoryType;
1861     PBL_MEMORY_DESCRIPTOR Descriptor;
1862     BL_MEMORY_ATTR Attribute;
1863     PVOID LibraryBuffer;
1864 
1865     /* Initialize EFI memory map attributes */
1866     EfiMemoryMapSize = MapKey = DescriptorSize = DescriptorVersion = 0;
1867     LibraryBuffer = NULL;
1868 
1869     /* Increment the nesting depth */
1870     MmDescriptorCallTreeCount++;
1871 
1872     /* Determine if we should use EFI or our own allocator at this point */
1873     UseEfiBuffer = Flags & BL_MM_FLAG_USE_FIRMWARE_FOR_MEMORY_MAP_BUFFERS;
1874     if (!(LibraryParameters.LibraryFlags & BL_LIBRARY_FLAG_INITIALIZATION_COMPLETED))
1875     {
1876         UseEfiBuffer = TRUE;
1877     }
1878 
1879     /* Bail out if we don't have a list to use */
1880     if (MemoryMap == NULL)
1881     {
1882         Status = STATUS_INVALID_PARAMETER;
1883         goto Quickie;
1884     }
1885 
1886     /* Free the current descriptor list */
1887     MmMdFreeList(MemoryMap);
1888 
1889     /* Call into EFI to get the size of the memory map */
1890     Status = EfiGetMemoryMap(&EfiMemoryMapSize,
1891                              NULL,
1892                              &MapKey,
1893                              &DescriptorSize,
1894                              &DescriptorVersion);
1895     if (Status != STATUS_BUFFER_TOO_SMALL)
1896     {
1897         /* This should've failed because our buffer was too small, nothing else */
1898         if (NT_SUCCESS(Status))
1899         {
1900             Status = STATUS_UNSUCCESSFUL;
1901         }
1902         goto Quickie;
1903     }
1904 
1905     /* Add 4 more descriptors just in case things changed */
1906     EfiMemoryMapSize += (4 * DescriptorSize);
1907     Pages = BYTES_TO_PAGES(EfiMemoryMapSize);
1908 
1909     /* Should we use EFI to grab memory? */
1910     if (UseEfiBuffer)
1911     {
1912         /* Yes -- request one more page to align up correctly */
1913         Pages++;
1914 
1915         /* Grab the required pages */
1916         Status = EfiAllocatePages(AllocateAnyPages,
1917                                   Pages,
1918                                   &EfiBuffer);
1919         if (!NT_SUCCESS(Status))
1920         {
1921             EfiPrintf(L"EFI allocation failed: %lx\r\n", Status);
1922             goto Quickie;
1923         }
1924 
1925         /* Free the pages for now */
1926         Status = EfiFreePages(Pages, EfiBuffer);
1927         if (!NT_SUCCESS(Status))
1928         {
1929             EfiBuffer = 0;
1930             goto Quickie;
1931         }
1932 
1933         /* Now round to the actual buffer size, removing the extra page */
1934         EfiBuffer = ROUND_TO_PAGES(EfiBuffer);
1935         Pages--;
1936         Status = EfiAllocatePages(AllocateAddress,
1937                                   Pages,
1938                                   &EfiBuffer);
1939         if (!NT_SUCCESS(Status))
1940         {
1941             EfiBuffer = 0;
1942             goto Quickie;
1943         }
1944 
1945         /* Get the final aligned size and proper buffer */
1946         EfiMemoryMapSize = EFI_PAGES_TO_SIZE(Pages);
1947         EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR*)(ULONG_PTR)EfiBuffer;
1948 
1949         /* Switch to real mode if not already in it */
1950         OldMode = CurrentExecutionContext->Mode;
1951         if (OldMode != BlRealMode)
1952         {
1953             BlpArchSwitchContext(BlRealMode);
1954         }
1955 
1956         /* Call EFI to get the memory map */
1957         EfiStatus = EfiBS->GetMemoryMap(&EfiMemoryMapSize,
1958                                         EfiMemoryMap,
1959                                         &MapKey,
1960                                         &DescriptorSize,
1961                                         &DescriptorVersion);
1962 
1963         /* Switch back into the previous mode */
1964         if (OldMode != BlRealMode)
1965         {
1966             BlpArchSwitchContext(OldMode);
1967         }
1968 
1969         /* Convert the result code */
1970         Status = EfiGetNtStatusCode(EfiStatus);
1971     }
1972     else
1973     {
1974         /* Round the map to pages */
1975         Pages = BYTES_TO_PAGES(EfiMemoryMapSize);
1976 
1977         /* Allocate a large enough buffer */
1978         Status = MmPapAllocatePagesInRange(&LibraryBuffer,
1979                                            BlLoaderData,
1980                                            Pages,
1981                                            0,
1982                                            0,
1983                                            0,
1984                                            0);
1985         if (!NT_SUCCESS(Status))
1986         {
1987             EfiPrintf(L"Failed to allocate mapped VM for EFI map: %lx\r\n", Status);
1988             goto Quickie;
1989         }
1990 
1991         /* Call EFI to get the memory map */
1992         EfiMemoryMap = LibraryBuffer;
1993         Status = EfiGetMemoryMap(&EfiMemoryMapSize,
1994                                  LibraryBuffer,
1995                                  &MapKey,
1996                                  &DescriptorSize,
1997                                  &DescriptorVersion);
1998     }
1999 
2000     /* So far so good? */
2001     if (!NT_SUCCESS(Status))
2002     {
2003         EfiPrintf(L"Failed to get EFI memory map: %lx\r\n", Status);
2004         goto Quickie;
2005     }
2006 
2007     /* Did we get correct data from firmware? */
2008     if (((EfiMemoryMapSize % DescriptorSize)) ||
2009         (DescriptorSize < sizeof(EFI_MEMORY_DESCRIPTOR)))
2010     {
2011         EfiPrintf(L"Incorrect descriptor size\r\n");
2012         Status = STATUS_UNSUCCESSFUL;
2013         goto Quickie;
2014     }
2015 
2016     /* Did we boot from a RAM disk? */
2017     if ((BlpBootDevice->DeviceType == LocalDevice) &&
2018         (BlpBootDevice->Local.Type == RamDiskDevice))
2019     {
2020         /* We don't handle this yet */
2021         EfiPrintf(L"RAM boot not supported\r\n");
2022         Status = STATUS_NOT_IMPLEMENTED;
2023         goto Quickie;
2024     }
2025     else
2026     {
2027         /* We didn't, so there won't be any need to find the memory descriptor */
2028         HaveRamDisk = FALSE;
2029     }
2030 
2031     /* Loop the EFI memory map */
2032 #if 0
2033     EfiPrintf(L"UEFI MEMORY MAP\r\n\r\n");
2034     EfiPrintf(L"TYPE        START              END                   ATTRIBUTES\r\n");
2035     EfiPrintf(L"===============================================================\r\n");
2036 #endif
2037     while (EfiMemoryMapSize != 0)
2038     {
2039         /* Check if this is an EFI buffer, but we're not in real mode */
2040         if ((UseEfiBuffer) && (OldMode != BlRealMode))
2041         {
2042             BlpArchSwitchContext(BlRealMode);
2043         }
2044 
2045         /* Capture it so we can go back to protected mode (if possible) */
2046         EfiDescriptor = *EfiMemoryMap;
2047 
2048         /* Go back to protected mode, if we had switched */
2049         if ((UseEfiBuffer) && (OldMode != BlRealMode))
2050         {
2051             BlpArchSwitchContext(OldMode);
2052         }
2053 
2054         /* Convert to OS memory type */
2055         MemoryType = MmFwpGetOsMemoryType(EfiDescriptor.Type);
2056 
2057         /* Round up or round down depending on where the memory is coming from */
2058         if (MemoryType == BlConventionalMemory)
2059         {
2060             StartPage = BYTES_TO_PAGES(EfiDescriptor.PhysicalStart);
2061         }
2062         else
2063         {
2064             StartPage = EfiDescriptor.PhysicalStart >> PAGE_SHIFT;
2065         }
2066 
2067         /* Calculate the ending page */
2068         EndPage = StartPage + EfiDescriptor.NumberOfPages;
2069 
2070         /* If after rounding, we ended up with 0 pages, skip this */
2071         if (StartPage == EndPage)
2072         {
2073             goto LoopAgain;
2074         }
2075 #if 0
2076         EfiPrintf(L"%08X    0x%016I64X-0x%016I64X    0x%I64X\r\n",
2077                    MemoryType,
2078                    StartPage << PAGE_SHIFT,
2079                    EndPage << PAGE_SHIFT,
2080                    EfiDescriptor.Attribute);
2081 #endif
2082         /* Check for any range of memory below 1MB */
2083         if (StartPage < 0x100)
2084         {
2085             /* Does this range actually contain NULL? */
2086             if (StartPage == 0)
2087             {
2088                 /* Manually create a reserved descriptof for this page */
2089                 Attribute = MmFwpGetOsAttributeType(EfiDescriptor.Attribute);
2090                 Descriptor = MmMdInitByteGranularDescriptor(Attribute,
2091                                                             BlReservedMemory,
2092                                                             0,
2093                                                             0,
2094                                                             1);
2095                 if (!Descriptor)
2096                 {
2097                     Status = STATUS_INSUFFICIENT_RESOURCES;
2098                     break;
2099                 }
2100 
2101                 /* Add this descriptor into the list */
2102                 Status = MmMdAddDescriptorToList(MemoryMap,
2103                                                  Descriptor,
2104                                                  BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG);
2105                 if (!NT_SUCCESS(Status))
2106                 {
2107                     EfiPrintf(L"Failed to add zero page descriptor: %lx\r\n", Status);
2108                     break;
2109                 }
2110 
2111                 /* Now handle the rest of the range, unless this was it */
2112                 StartPage = 1;
2113                 if (EndPage == 1)
2114                 {
2115                     goto LoopAgain;
2116                 }
2117             }
2118 
2119             /* Does the range go beyond 1MB? */
2120             if (EndPage > 0x100)
2121             {
2122                 /* Then create the descriptor for everything up until the megabyte */
2123                 Attribute = MmFwpGetOsAttributeType(EfiDescriptor.Attribute);
2124                 Descriptor = MmMdInitByteGranularDescriptor(Attribute,
2125                                                             MemoryType,
2126                                                             StartPage,
2127                                                             0,
2128                                                             0x100 - StartPage);
2129                 if (!Descriptor)
2130                 {
2131                     Status = STATUS_INSUFFICIENT_RESOURCES;
2132                     break;
2133                 }
2134 
2135                 /* Check if this region is currently free RAM */
2136                 if (Descriptor->Type == BlConventionalMemory)
2137                 {
2138                     /* Set the appropriate flag on the descriptor */
2139                     Descriptor->Flags |= BlMemoryBelow1MB;
2140                 }
2141 
2142                 /* Add this descriptor into the list */
2143                 Status = MmMdAddDescriptorToList(MemoryMap,
2144                                                  Descriptor,
2145                                                  BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG);
2146                 if (!NT_SUCCESS(Status))
2147                 {
2148                     EfiPrintf(L"Failed to add 1MB descriptor: %lx\r\n", Status);
2149                     break;
2150                 }
2151 
2152                 /* Now handle the rest of the range above 1MB */
2153                 StartPage = 0x100;
2154             }
2155         }
2156 
2157         /* Check if we loaded from a RAM disk */
2158         if (HaveRamDisk)
2159         {
2160             /* We don't handle this yet */
2161             EfiPrintf(L"RAM boot not supported\r\n");
2162             Status = STATUS_NOT_IMPLEMENTED;
2163             goto Quickie;
2164         }
2165 
2166         /* Create a descriptor for the current range */
2167         Attribute = MmFwpGetOsAttributeType(EfiDescriptor.Attribute);
2168         Descriptor = MmMdInitByteGranularDescriptor(Attribute,
2169                                                     MemoryType,
2170                                                     StartPage,
2171                                                     0,
2172                                                     EndPage - StartPage);
2173         if (!Descriptor)
2174         {
2175             Status = STATUS_INSUFFICIENT_RESOURCES;
2176             break;
2177         }
2178 
2179         /* Check if this region is currently free RAM below 1MB */
2180         if ((Descriptor->Type == BlConventionalMemory) && (EndPage <= 0x100))
2181         {
2182             /* Set the appropriate flag on the descriptor */
2183             Descriptor->Flags |= BlMemoryBelow1MB;
2184         }
2185 
2186         /* Add the descriptor to the list, requesting coalescing as asked */
2187         Status = MmMdAddDescriptorToList(MemoryMap,
2188                                          Descriptor,
2189                                          BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG |
2190                                          ((Flags & BL_MM_FLAG_REQUEST_COALESCING) ?
2191                                           BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG : 0));
2192         if (!NT_SUCCESS(Status))
2193         {
2194             EfiPrintf(L"Failed to add full descriptor: %lx\r\n", Status);
2195             break;
2196         }
2197 
2198 LoopAgain:
2199         /* Consume this descriptor, and move to the next one */
2200         EfiMemoryMapSize -= DescriptorSize;
2201         EfiMemoryMap = (PVOID)((ULONG_PTR)EfiMemoryMap + DescriptorSize);
2202     }
2203 
2204     /* Check if we are using the local UEFI buffer */
2205     if (!UseEfiBuffer)
2206     {
2207         goto Quickie;
2208     }
2209 
2210     /* Free the EFI buffer */
2211     Status = EfiFreePages(Pages, EfiBuffer);
2212     if (!NT_SUCCESS(Status))
2213     {
2214         /* Keep the pages marked 'in use' and fake success */
2215         Status = STATUS_SUCCESS;
2216         goto Quickie;
2217     }
2218 
2219     /* Get the base page of the EFI buffer */
2220     EfiBufferPage = EfiBuffer >> PAGE_SHIFT;
2221     Pages = (EfiBufferPage + Pages) - EfiBufferPage;
2222 
2223     /* Don't try freeing below */
2224     EfiBuffer = 0;
2225 
2226     /* Find the current descriptor for the allocation */
2227     Descriptor = MmMdFindDescriptorFromMdl(MemoryMap,
2228                                            BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
2229                                            EfiBufferPage);
2230     if (!Descriptor)
2231     {
2232         Status = STATUS_UNSUCCESSFUL;
2233         goto Quickie;
2234     }
2235 
2236     /* Convert it to a free descriptor */
2237     Descriptor = MmMdInitByteGranularDescriptor(Descriptor->Flags,
2238                                                 BlConventionalMemory,
2239                                                 EfiBufferPage,
2240                                                 0,
2241                                                 Pages);
2242     if (!Descriptor)
2243     {
2244         Status = STATUS_INSUFFICIENT_RESOURCES;
2245         goto Quickie;
2246     }
2247 
2248     /* Remove the region from the memory map */
2249     Status = MmMdRemoveRegionFromMdlEx(MemoryMap,
2250                                        BL_MM_REMOVE_PHYSICAL_REGION_FLAG,
2251                                        EfiBufferPage,
2252                                        Pages,
2253                                        NULL);
2254     if (!NT_SUCCESS(Status))
2255     {
2256         MmMdFreeDescriptor(Descriptor);
2257         goto Quickie;
2258     }
2259 
2260     /* Add it back as free memory */
2261     Status = MmMdAddDescriptorToList(MemoryMap,
2262                                      Descriptor,
2263                                      BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG);
2264 
2265 Quickie:
2266     /* Free the EFI buffer, if we had one */
2267     if (EfiBuffer != 0)
2268     {
2269         EfiFreePages(Pages, EfiBuffer);
2270     }
2271 
2272     /* Free the library-allocated buffer, if we had one */
2273     if (LibraryBuffer != 0)
2274     {
2275         MmPapFreePages(LibraryBuffer, BL_MM_INCLUDE_MAPPED_ALLOCATED);
2276     }
2277 
2278     /* On failure, free the memory map if one was passed in */
2279     if (!NT_SUCCESS(Status) && (MemoryMap != NULL))
2280     {
2281         MmMdFreeList(MemoryMap);
2282     }
2283 
2284     /* Decrement the nesting depth and return */
2285     MmDescriptorCallTreeCount--;
2286     return Status;
2287 }
2288 
2289 NTSTATUS
BlpFwInitialize(_In_ ULONG Phase,_In_ PBL_FIRMWARE_DESCRIPTOR FirmwareData)2290 BlpFwInitialize (
2291     _In_ ULONG Phase,
2292     _In_ PBL_FIRMWARE_DESCRIPTOR FirmwareData
2293     )
2294 {
2295     NTSTATUS Status = STATUS_SUCCESS;
2296     EFI_KEY_TOGGLE_STATE KeyToggleState;
2297 
2298     /* Check if we have valid firmware data */
2299     if (!(FirmwareData) || !(FirmwareData->Version))
2300     {
2301         return STATUS_INVALID_PARAMETER;
2302     }
2303 
2304     /* Check which boot phase we're in */
2305     if (Phase != 0)
2306     {
2307         /* Memory manager is ready, open the extended input protocol */
2308         Status = EfiOpenProtocol(EfiST->ConsoleInHandle,
2309                                  &EfiSimpleTextInputExProtocol,
2310                                  (PVOID*)&EfiConInEx);
2311         if (NT_SUCCESS(Status))
2312         {
2313             /* Set the initial key toggle state */
2314             KeyToggleState = EFI_TOGGLE_STATE_VALID | 40;
2315             EfiConInExSetState(EfiConInEx, &KeyToggleState);
2316         }
2317 
2318         /* Setup the watchdog timer */
2319         EfiSetWatchdogTimer();
2320     }
2321     else
2322     {
2323         /* Make a copy of the parameters */
2324         EfiFirmwareParameters = &EfiFirmwareData;
2325 
2326         /* Check which version we received */
2327         if (FirmwareData->Version == 1)
2328         {
2329             /* FIXME: Not supported */
2330             Status = STATUS_NOT_SUPPORTED;
2331         }
2332         else if (FirmwareData->Version >= BL_FIRMWARE_DESCRIPTOR_VERSION)
2333         {
2334             /* Version 2 -- save the data */
2335             EfiFirmwareData = *FirmwareData;
2336             EfiSystemTable = FirmwareData->SystemTable;
2337             EfiImageHandle = FirmwareData->ImageHandle;
2338 
2339             /* Set the EDK-II style variables as well */
2340             EfiST = EfiSystemTable;
2341             EfiBS = EfiSystemTable->BootServices;
2342             EfiRT = EfiSystemTable->RuntimeServices;
2343             EfiConOut = EfiSystemTable->ConOut;
2344             EfiConIn = EfiSystemTable->ConIn;
2345             EfiConInEx = NULL;
2346         }
2347         else
2348         {
2349             /* Unknown version */
2350             Status = STATUS_NOT_SUPPORTED;
2351         }
2352     }
2353 
2354     /* Return the initialization state */
2355     return Status;
2356 }
2357 
2358 NTSTATUS
BlFwGetParameters(_In_ PBL_FIRMWARE_DESCRIPTOR Parameters)2359 BlFwGetParameters (
2360     _In_ PBL_FIRMWARE_DESCRIPTOR Parameters
2361     )
2362 {
2363     /* Make sure we got an argument */
2364     if (!Parameters)
2365     {
2366         return STATUS_INVALID_PARAMETER;
2367     }
2368 
2369     /* Copy the static data */
2370     *Parameters = *EfiFirmwareParameters;
2371     return STATUS_SUCCESS;
2372 }
2373 
2374 NTSTATUS
BlFwEnumerateDevice(_In_ PBL_DEVICE_DESCRIPTOR Device)2375 BlFwEnumerateDevice (
2376     _In_ PBL_DEVICE_DESCRIPTOR Device
2377     )
2378 {
2379     NTSTATUS Status;
2380     ULONG PathProtocols, BlockProtocols;
2381     EFI_HANDLE* PathArray;
2382     EFI_HANDLE* BlockArray;
2383 
2384     /* Initialize locals */
2385     BlockArray = NULL;
2386     PathArray = NULL;
2387     PathProtocols = 0;
2388     BlockProtocols = 0;
2389 
2390     /* Enumeration only makes sense on disks or partitions */
2391     if ((Device->DeviceType != DiskDevice) &&
2392         (Device->DeviceType != LegacyPartitionDevice) &&
2393         (Device->DeviceType != PartitionDevice))
2394     {
2395         return STATUS_NOT_SUPPORTED;
2396     }
2397 
2398     /* Enumerate the list of device paths */
2399     Status = EfiLocateHandleBuffer(ByProtocol,
2400                                    &EfiDevicePathProtocol,
2401                                    &PathProtocols,
2402                                    &PathArray);
2403     if (NT_SUCCESS(Status))
2404     {
2405         /* Loop through each one */
2406         Status = STATUS_NOT_FOUND;
2407         while (PathProtocols)
2408         {
2409             /* Attempt to connect the driver for this device epath */
2410             Status = EfiConnectController(PathArray[--PathProtocols]);
2411             if (NT_SUCCESS(Status))
2412             {
2413                 /* Now enumerate any block I/O devices the driver added */
2414                 Status = EfiLocateHandleBuffer(ByProtocol,
2415                                                &EfiBlockIoProtocol,
2416                                                &BlockProtocols,
2417                                                &BlockArray);
2418                 if (!NT_SUCCESS(Status))
2419                 {
2420                     break;
2421                 }
2422 
2423                 /* Loop through each one */
2424                 while (BlockProtocols)
2425                 {
2426                     /* Check if one of the new devices is the one we want */
2427                     Status = BlockIoEfiCompareDevice(Device,
2428                                                      BlockArray[--BlockProtocols]);
2429                     if (NT_SUCCESS(Status))
2430                     {
2431                         /* Yep, all done */
2432                         goto Quickie;
2433                     }
2434                 }
2435 
2436                 /* Move on to the next device path */
2437                 BlMmFreeHeap(BlockArray);
2438                 BlockArray = NULL;
2439             }
2440         }
2441     }
2442 
2443 Quickie:
2444     /* We're done -- free the array of device path protocols, if any */
2445     if (PathArray)
2446     {
2447         BlMmFreeHeap(PathArray);
2448     }
2449 
2450     /* We're done -- free the array of block I/O protocols, if any */
2451     if (BlockArray)
2452     {
2453         BlMmFreeHeap(BlockArray);
2454     }
2455 
2456     /* Return if we found the device or not */
2457     return Status;
2458 }
2459 
2460 /*++
2461  * @name EfiGetEfiStatusCode
2462  *
2463  *     The EfiGetEfiStatusCode routine converts an NT Status to an EFI status.
2464  *
2465  * @param  Status
2466  *         NT Status code to be converted.
2467  *
2468  * @remark Only certain, specific NT status codes are converted to EFI codes.
2469  *
2470  * @return The corresponding EFI Status code, EFI_NO_MAPPING otherwise.
2471  *
2472  *--*/
2473 EFI_STATUS
EfiGetEfiStatusCode(_In_ NTSTATUS Status)2474 EfiGetEfiStatusCode(
2475     _In_ NTSTATUS Status
2476     )
2477 {
2478     switch (Status)
2479     {
2480         case STATUS_NOT_SUPPORTED:
2481             return EFI_UNSUPPORTED;
2482         case STATUS_DISK_FULL:
2483             return EFI_VOLUME_FULL;
2484         case STATUS_INSUFFICIENT_RESOURCES:
2485             return EFI_OUT_OF_RESOURCES;
2486         case STATUS_MEDIA_WRITE_PROTECTED:
2487             return EFI_WRITE_PROTECTED;
2488         case STATUS_DEVICE_NOT_READY:
2489             return EFI_NOT_STARTED;
2490         case STATUS_DEVICE_ALREADY_ATTACHED:
2491             return EFI_ALREADY_STARTED;
2492         case STATUS_MEDIA_CHANGED:
2493             return EFI_MEDIA_CHANGED;
2494         case STATUS_INVALID_PARAMETER:
2495             return EFI_INVALID_PARAMETER;
2496         case STATUS_ACCESS_DENIED:
2497             return EFI_ACCESS_DENIED;
2498         case STATUS_BUFFER_TOO_SMALL:
2499             return EFI_BUFFER_TOO_SMALL;
2500         case STATUS_DISK_CORRUPT_ERROR:
2501             return EFI_VOLUME_CORRUPTED;
2502         case STATUS_REQUEST_ABORTED:
2503             return EFI_ABORTED;
2504         case STATUS_NO_MEDIA:
2505             return EFI_NO_MEDIA;
2506         case STATUS_IO_DEVICE_ERROR:
2507             return EFI_DEVICE_ERROR;
2508         case STATUS_INVALID_BUFFER_SIZE:
2509             return EFI_BAD_BUFFER_SIZE;
2510         case STATUS_NOT_FOUND:
2511             return EFI_NOT_FOUND;
2512         case STATUS_DRIVER_UNABLE_TO_LOAD:
2513             return EFI_LOAD_ERROR;
2514         case STATUS_NO_MATCH:
2515             return EFI_NO_MAPPING;
2516         case STATUS_SUCCESS:
2517             return EFI_SUCCESS;
2518         case STATUS_TIMEOUT:
2519             return EFI_TIMEOUT;
2520         default:
2521             return EFI_NO_MAPPING;
2522     }
2523 }
2524 
2525 /*++
2526  * @name EfiGetNtStatusCode
2527  *
2528  *     The EfiGetNtStatusCode routine converts an EFI Status to an NT status.
2529  *
2530  * @param  EfiStatus
2531  *         EFI Status code to be converted.
2532  *
2533  * @remark Only certain, specific EFI status codes are converted to NT codes.
2534  *
2535  * @return The corresponding NT Status code, STATUS_UNSUCCESSFUL otherwise.
2536  *
2537  *--*/
2538 NTSTATUS
EfiGetNtStatusCode(_In_ EFI_STATUS EfiStatus)2539 EfiGetNtStatusCode (
2540     _In_ EFI_STATUS EfiStatus
2541     )
2542 {
2543     switch (EfiStatus)
2544     {
2545         case EFI_NOT_READY:
2546         case EFI_NOT_FOUND:
2547             return STATUS_NOT_FOUND;
2548         case EFI_NO_MEDIA:
2549             return STATUS_NO_MEDIA;
2550         case EFI_MEDIA_CHANGED:
2551             return STATUS_MEDIA_CHANGED;
2552         case EFI_ACCESS_DENIED:
2553         case EFI_SECURITY_VIOLATION:
2554             return STATUS_ACCESS_DENIED;
2555         case EFI_TIMEOUT:
2556         case EFI_NO_RESPONSE:
2557             return STATUS_TIMEOUT;
2558         case EFI_NO_MAPPING:
2559             return STATUS_NO_MATCH;
2560         case EFI_NOT_STARTED:
2561             return STATUS_DEVICE_NOT_READY;
2562         case EFI_ALREADY_STARTED:
2563             return STATUS_DEVICE_ALREADY_ATTACHED;
2564         case EFI_ABORTED:
2565             return STATUS_REQUEST_ABORTED;
2566         case EFI_VOLUME_FULL:
2567             return STATUS_DISK_FULL;
2568         case EFI_DEVICE_ERROR:
2569             return STATUS_IO_DEVICE_ERROR;
2570         case EFI_WRITE_PROTECTED:
2571             return STATUS_MEDIA_WRITE_PROTECTED;
2572         /* @FIXME: ReactOS Headers don't yet have this */
2573         //case EFI_OUT_OF_RESOURCES:
2574             //return STATUS_INSUFFICIENT_NVRAM_RESOURCES;
2575         case EFI_VOLUME_CORRUPTED:
2576             return STATUS_DISK_CORRUPT_ERROR;
2577         case EFI_BUFFER_TOO_SMALL:
2578             return STATUS_BUFFER_TOO_SMALL;
2579         case EFI_SUCCESS:
2580             return STATUS_SUCCESS;
2581         case  EFI_LOAD_ERROR:
2582             return STATUS_DRIVER_UNABLE_TO_LOAD;
2583         case EFI_INVALID_PARAMETER:
2584             return STATUS_INVALID_PARAMETER;
2585         case EFI_UNSUPPORTED:
2586             return STATUS_NOT_SUPPORTED;
2587         case EFI_BAD_BUFFER_SIZE:
2588             return STATUS_INVALID_BUFFER_SIZE;
2589         default:
2590             return STATUS_UNSUCCESSFUL;
2591     }
2592 }
2593