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)
9 /* INCLUDES ******************************************************************/
13 /* DATA VARIABLES ************************************************************/
15 GUID EfiSimpleTextInputExProtocol
= EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID
;
17 PBL_FIRMWARE_DESCRIPTOR EfiFirmwareParameters
;
18 BL_FIRMWARE_DESCRIPTOR EfiFirmwareData
;
19 EFI_HANDLE EfiImageHandle
;
20 EFI_SYSTEM_TABLE
* EfiSystemTable
;
22 EFI_SYSTEM_TABLE
*EfiST
;
23 EFI_BOOT_SERVICES
*EfiBS
;
24 EFI_RUNTIME_SERVICES
*EfiRT
;
25 EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
*EfiConOut
;
26 EFI_SIMPLE_TEXT_INPUT_PROTOCOL
*EfiConIn
;
27 EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*EfiConInEx
;
29 /* FUNCTIONS *****************************************************************/
33 _In_ EFI_HANDLE Handle
,
34 _In_ EFI_GUID
*Protocol
,
35 _Out_ PVOID
* Interface
42 /* Are we using virtual memory/ */
43 if (MmTranslationType
!= BlNone
)
45 /* We need complex tracking to make this work */
46 //Status = EfiVmOpenProtocol(Handle, Protocol, Interface);
47 Status
= STATUS_NOT_SUPPORTED
;
51 /* Are we in protected mode? */
52 OldMode
= CurrentExecutionContext
->Mode
;
53 if (OldMode
!= BlRealMode
)
55 /* FIXME: Not yet implemented */
56 return STATUS_NOT_IMPLEMENTED
;
59 /* Are we on legacy 1.02? */
60 if (EfiST
->FirmwareRevision
== EFI_1_02_SYSTEM_TABLE_REVISION
)
62 /* Make the legacy call */
63 EfiStatus
= EfiBS
->HandleProtocol(Handle
, Protocol
, Interface
);
67 /* Use the UEFI version */
68 EfiStatus
= EfiBS
->OpenProtocol(Handle
,
73 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
75 /* Switch back to protected mode if we came from there */
76 if (OldMode
!= BlRealMode
)
78 BlpArchSwitchContext(OldMode
);
82 /* Convert the error to an NTSTATUS */
83 Status
= EfiGetNtStatusCode(EfiStatus
);
86 /* Clear the interface on failure, and return the status */
87 if (!NT_SUCCESS(Status
))
97 _In_ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL
*ConInEx
,
98 _In_ EFI_KEY_TOGGLE_STATE
* KeyToggleState
101 BL_ARCH_MODE OldMode
;
102 EFI_STATUS EfiStatus
;
104 /* Are we in protected mode? */
105 OldMode
= CurrentExecutionContext
->Mode
;
106 if (OldMode
!= BlRealMode
)
108 /* FIXME: Not yet implemented */
109 return STATUS_NOT_IMPLEMENTED
;
112 /* Make the EFI call */
113 EfiStatus
= ConInEx
->SetState(ConInEx
, KeyToggleState
);
115 /* Switch back to protected mode if we came from there */
116 if (OldMode
!= BlRealMode
)
118 BlpArchSwitchContext(OldMode
);
121 /* Convert the error to an NTSTATUS */
122 return EfiGetNtStatusCode(EfiStatus
);
126 EfiSetWatchdogTimer (
130 BL_ARCH_MODE OldMode
;
131 EFI_STATUS EfiStatus
;
133 /* Are we in protected mode? */
134 OldMode
= CurrentExecutionContext
->Mode
;
135 if (OldMode
!= BlRealMode
)
137 /* FIXME: Not yet implemented */
138 return STATUS_NOT_IMPLEMENTED
;
141 /* Make the EFI call */
142 EfiStatus
= EfiBS
->SetWatchdogTimer(0, 0, 0, NULL
);
144 /* Switch back to protected mode if we came from there */
145 if (OldMode
!= BlRealMode
)
147 BlpArchSwitchContext(OldMode
);
150 /* Convert the error to an NTSTATUS */
151 return EfiGetNtStatusCode(EfiStatus
);
156 _Out_ UINTN
* MemoryMapSize
,
157 _Inout_ EFI_MEMORY_DESCRIPTOR
*MemoryMap
,
159 _Out_ UINTN
* DescriptorSize
,
160 _Out_ UINTN
* DescriptorVersion
163 BL_ARCH_MODE OldMode
;
164 EFI_STATUS EfiStatus
;
166 /* Are we in protected mode? */
167 OldMode
= CurrentExecutionContext
->Mode
;
168 if (OldMode
!= BlRealMode
)
170 /* FIXME: Not yet implemented */
171 return STATUS_NOT_IMPLEMENTED
;
174 /* Make the EFI call */
175 EfiStatus
= EfiBS
->GetMemoryMap(MemoryMapSize
,
181 /* Switch back to protected mode if we came from there */
182 if (OldMode
!= BlRealMode
)
184 BlpArchSwitchContext(OldMode
);
187 /* Convert the error to an NTSTATUS */
188 return EfiGetNtStatusCode(EfiStatus
);
194 _In_ EFI_PHYSICAL_ADDRESS PhysicalAddress
197 BL_ARCH_MODE OldMode
;
198 EFI_STATUS EfiStatus
;
200 /* Are we in protected mode? */
201 OldMode
= CurrentExecutionContext
->Mode
;
202 if (OldMode
!= BlRealMode
)
204 /* FIXME: Not yet implemented */
205 return STATUS_NOT_IMPLEMENTED
;
208 /* Make the EFI call */
209 EfiStatus
= EfiBS
->FreePages(PhysicalAddress
, Pages
);
211 /* Switch back to protected mode if we came from there */
212 if (OldMode
!= BlRealMode
)
214 BlpArchSwitchContext(OldMode
);
217 /* Convert the error to an NTSTATUS */
218 return EfiGetNtStatusCode(EfiStatus
);
226 BL_ARCH_MODE OldMode
;
227 EFI_STATUS EfiStatus
;
229 /* Are we in protected mode? */
230 OldMode
= CurrentExecutionContext
->Mode
;
231 if (OldMode
!= BlRealMode
)
233 /* FIXME: Not yet implemented */
234 return STATUS_NOT_IMPLEMENTED
;
237 /* Make the EFI call */
238 EfiStatus
= EfiBS
->Stall(StallTime
);
240 /* Switch back to protected mode if we came from there */
241 if (OldMode
!= BlRealMode
)
243 BlpArchSwitchContext(OldMode
);
246 /* Convert the error to an NTSTATUS */
247 return EfiGetNtStatusCode(EfiStatus
);
254 _Inout_ EFI_PHYSICAL_ADDRESS
* Memory
257 BL_ARCH_MODE OldMode
;
258 EFI_STATUS EfiStatus
;
260 /* Are we in protected mode? */
261 OldMode
= CurrentExecutionContext
->Mode
;
262 if (OldMode
!= BlRealMode
)
264 /* FIXME: Not yet implemented */
265 return STATUS_NOT_IMPLEMENTED
;
268 /* Make the EFI call */
269 EfiStatus
= EfiBS
->AllocatePages(Type
, EfiLoaderData
, Pages
, Memory
);
271 /* Switch back to protected mode if we came from there */
272 if (OldMode
!= BlRealMode
)
274 BlpArchSwitchContext(OldMode
);
277 /* Convert the error to an NTSTATUS */
278 return EfiGetNtStatusCode(EfiStatus
);
282 MmFwpGetOsAttributeType (
283 _In_ ULONGLONG Attribute
286 BL_MEMORY_ATTR OsAttribute
= 0;
288 if (Attribute
& EFI_MEMORY_UC
)
290 OsAttribute
= BlMemoryUncached
;
293 if (Attribute
& EFI_MEMORY_WC
)
295 OsAttribute
|= BlMemoryWriteCombined
;
298 if (Attribute
& EFI_MEMORY_WT
)
300 OsAttribute
|= BlMemoryWriteThrough
;
303 if (Attribute
& EFI_MEMORY_WB
)
305 OsAttribute
|= BlMemoryWriteBack
;
308 if (Attribute
& EFI_MEMORY_UCE
)
310 OsAttribute
|= BlMemoryUncachedExported
;
313 if (Attribute
& EFI_MEMORY_WP
)
315 OsAttribute
|= BlMemoryWriteProtected
;
318 if (Attribute
& EFI_MEMORY_RP
)
320 OsAttribute
|= BlMemoryReadProtected
;
323 if (Attribute
& EFI_MEMORY_XP
)
325 OsAttribute
|= BlMemoryExecuteProtected
;
328 if (Attribute
& EFI_MEMORY_RUNTIME
)
330 OsAttribute
|= BlMemoryRuntime
;
337 MmFwpGetOsMemoryType (
338 _In_ EFI_MEMORY_TYPE MemoryType
341 BL_MEMORY_TYPE OsType
;
347 OsType
= BlLoaderMemory
;
350 case EfiBootServicesCode
:
351 case EfiBootServicesData
:
352 OsType
= BlEfiBootMemory
;
355 case EfiRuntimeServicesCode
:
356 case EfiRuntimeServicesData
:
357 OsType
= BlEfiRuntimeMemory
;
360 case EfiConventionalMemory
:
361 OsType
= BlConventionalMemory
;
364 case EfiUnusableMemory
:
365 OsType
= BlUnusableMemory
;
368 case EfiACPIReclaimMemory
:
369 OsType
= BlAcpiReclaimMemory
;
372 case EfiACPIMemoryNVS
:
373 OsType
= BlAcpiNvsMemory
;
376 case EfiMemoryMappedIO
:
377 OsType
= BlDeviceIoMemory
;
380 case EfiMemoryMappedIOPortSpace
:
381 OsType
= BlDevicePortMemory
;
385 OsType
= BlPalMemory
;
389 OsType
= BlReservedMemory
;
398 _Out_ PBL_MEMORY_DESCRIPTOR_LIST MemoryMap
,
402 BL_LIBRARY_PARAMETERS LibraryParameters
= BlpLibraryParameters
;
403 BOOLEAN UseEfiBuffer
, HaveRamDisk
;
405 ULONGLONG Pages
, StartPage
, EndPage
;
406 UINTN EfiMemoryMapSize
, MapKey
, DescriptorSize
, DescriptorVersion
;
407 EFI_PHYSICAL_ADDRESS EfiBuffer
;
408 EFI_MEMORY_DESCRIPTOR
* EfiMemoryMap
;
409 EFI_STATUS EfiStatus
;
410 BL_ARCH_MODE OldMode
;
411 EFI_MEMORY_DESCRIPTOR EfiDescriptor
;
412 BL_MEMORY_TYPE MemoryType
;
413 PBL_MEMORY_DESCRIPTOR Descriptor
;
414 BL_MEMORY_ATTR Attribute
;
416 /* Initialize EFI memory map attributes */
417 EfiMemoryMapSize
= MapKey
= DescriptorSize
= DescriptorVersion
= 0;
419 /* Increment the nesting depth */
420 MmDescriptorCallTreeCount
++;
422 /* Determine if we should use EFI or our own allocator at this point */
423 UseEfiBuffer
= Flags
& BL_MM_FLAG_USE_FIRMWARE_FOR_MEMORY_MAP_BUFFERS
;
424 if (!(LibraryParameters
.LibraryFlags
& BL_LIBRARY_FLAG_INITIALIZATION_COMPLETED
))
429 /* Bail out if we don't have a list to use */
430 if (MemoryMap
== NULL
)
432 Status
= STATUS_INVALID_PARAMETER
;
436 /* Free the current descriptor list */
437 MmMdFreeList(MemoryMap
);
439 /* Call into EFI to get the size of the memory map */
440 Status
= EfiGetMemoryMap(&EfiMemoryMapSize
,
445 if (Status
!= STATUS_BUFFER_TOO_SMALL
)
447 /* This should've failed because our buffer was too small, nothing else */
448 EarlyPrint(L
"Got strange EFI status for memory map: %lx\n", Status
);
449 if (NT_SUCCESS(Status
))
451 Status
= STATUS_UNSUCCESSFUL
;
456 /* Add 4 more descriptors just in case things changed */
457 EfiMemoryMapSize
+= (4 * DescriptorSize
);
458 Pages
= BYTES_TO_PAGES(EfiMemoryMapSize
);
459 EarlyPrint(L
"Memory map size: %lx bytes, %d pages\n", EfiMemoryMapSize
, Pages
);
461 /* Should we use EFI to grab memory? */
464 /* Yes -- request one more page to align up correctly */
467 /* Grab the required pages */
468 Status
= EfiAllocatePages(AllocateAnyPages
,
471 if (!NT_SUCCESS(Status
))
473 EarlyPrint(L
"EFI allocation failed: %lx\n", Status
);
477 /* Free the pages for now */
478 Status
= EfiFreePages(Pages
, EfiBuffer
);
479 if (!NT_SUCCESS(Status
))
485 /* Now round to the actual buffer size, removing the extra page */
486 EfiBuffer
= ROUND_TO_PAGES(EfiBuffer
);
488 Status
= EfiAllocatePages(AllocateAddress
,
491 if (!NT_SUCCESS(Status
))
497 /* Get the final aligned size and proper buffer */
498 EfiMemoryMapSize
= EFI_PAGES_TO_SIZE(Pages
);
499 EfiMemoryMap
= (EFI_MEMORY_DESCRIPTOR
*)(ULONG_PTR
)EfiBuffer
;
501 /* Switch to real mode if not already in it */
502 OldMode
= CurrentExecutionContext
->Mode
;
503 if (OldMode
!= BlRealMode
)
505 BlpArchSwitchContext(BlRealMode
);
508 /* Call EFI to get the memory map */
509 EfiStatus
= EfiBS
->GetMemoryMap(&EfiMemoryMapSize
,
515 /* Switch back into the previous mode */
516 if (OldMode
!= BlRealMode
)
518 BlpArchSwitchContext(OldMode
);
521 /* Convert the result code */
522 Status
= EfiGetNtStatusCode(EfiStatus
);
526 /* We don't support this path yet */
527 Status
= STATUS_NOT_IMPLEMENTED
;
530 /* So far so good? */
531 if (!NT_SUCCESS(Status
))
533 EarlyPrint(L
"Failed to get EFI memory map: %lx\n", Status
);
537 /* Did we get correct data from firmware? */
538 if (((EfiMemoryMapSize
% DescriptorSize
)) ||
539 (DescriptorSize
< sizeof(EFI_MEMORY_DESCRIPTOR
)))
541 EarlyPrint(L
"Incorrect descriptor size\n");
542 Status
= STATUS_UNSUCCESSFUL
;
546 /* Did we boot from a RAM disk? */
547 if ((BlpBootDevice
->DeviceType
== LocalDevice
) &&
548 (BlpBootDevice
->Local
.Type
== RamDiskDevice
))
550 /* We don't handle this yet */
551 EarlyPrint(L
"RAM boot not supported\n");
552 Status
= STATUS_NOT_IMPLEMENTED
;
557 /* We didn't, so there won't be any need to find the memory descriptor */
561 /* Loop the EFI memory map */
563 EarlyPrint(L
"UEFI MEMORY MAP\n\n");
564 EarlyPrint(L
"TYPE START END ATTRIBUTES\n");
565 EarlyPrint(L
"===============================================================\n");
567 while (EfiMemoryMapSize
!= 0)
569 /* Check if this is an EFI buffer, but we're not in real mode */
570 if ((UseEfiBuffer
) && (OldMode
!= BlRealMode
))
572 BlpArchSwitchContext(BlRealMode
);
575 /* Capture it so we can go back to protected mode (if possible) */
576 EfiDescriptor
= *EfiMemoryMap
;
578 /* Go back to protected mode, if we had switched */
579 if ((UseEfiBuffer
) && (OldMode
!= BlRealMode
))
581 BlpArchSwitchContext(OldMode
);
584 /* Convert to OS memory type */
585 MemoryType
= MmFwpGetOsMemoryType(EfiDescriptor
.Type
);
587 /* Round up or round down depending on where the memory is coming from */
588 if (MemoryType
== BlConventionalMemory
)
590 StartPage
= BYTES_TO_PAGES(EfiDescriptor
.PhysicalStart
);
594 StartPage
= EfiDescriptor
.PhysicalStart
>> PAGE_SHIFT
;
597 /* Calculate the ending page */
598 EndPage
= StartPage
+ EfiDescriptor
.NumberOfPages
;
600 /* If after rounding, we ended up with 0 pages, skip this */
601 if (StartPage
== EndPage
)
606 EarlyPrint(L
"%08X 0x%016I64X-0x%016I64X 0x%I64X\n",
608 StartPage
<< PAGE_SHIFT
,
609 EndPage
<< PAGE_SHIFT
,
610 EfiDescriptor
.Attribute
);
612 /* Check for any range of memory below 1MB */
613 if (StartPage
< 0x100)
615 /* Does this range actually contain NULL? */
618 /* Manually create a reserved descriptof for this page */
619 Attribute
= MmFwpGetOsAttributeType(EfiDescriptor
.Attribute
);
620 Descriptor
= MmMdInitByteGranularDescriptor(Attribute
,
627 Status
= STATUS_INSUFFICIENT_RESOURCES
;
631 /* Add this descriptor into the list */
632 Status
= MmMdAddDescriptorToList(MemoryMap
,
634 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG
);
635 if (!NT_SUCCESS(Status
))
637 EarlyPrint(L
"Failed to add zero page descriptor: %lx\n", Status
);
641 /* Now handle the rest of the range, unless this was it */
649 /* Does the range go beyond 1MB? */
652 /* Then create the descriptor for everything up until the megabyte */
653 Attribute
= MmFwpGetOsAttributeType(EfiDescriptor
.Attribute
);
654 Descriptor
= MmMdInitByteGranularDescriptor(Attribute
,
661 Status
= STATUS_INSUFFICIENT_RESOURCES
;
665 /* Check if this region is currently free RAM */
666 if (Descriptor
->Type
== BlConventionalMemory
)
668 /* Set an unknown flag on the descriptor */
669 Descriptor
->Flags
|= 0x80000;
672 /* Add this descriptor into the list */
673 Status
= MmMdAddDescriptorToList(MemoryMap
,
675 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG
);
676 if (!NT_SUCCESS(Status
))
678 EarlyPrint(L
"Failed to add 1MB descriptor: %lx\n", Status
);
682 /* Now handle the rest of the range above 1MB */
687 /* Check if we loaded from a RAM disk */
690 /* We don't handle this yet */
691 EarlyPrint(L
"RAM boot not supported\n");
692 Status
= STATUS_NOT_IMPLEMENTED
;
696 /* Create a descriptor for the current range */
697 Attribute
= MmFwpGetOsAttributeType(EfiDescriptor
.Attribute
);
698 Descriptor
= MmMdInitByteGranularDescriptor(Attribute
,
702 EndPage
- StartPage
);
705 Status
= STATUS_INSUFFICIENT_RESOURCES
;
709 /* Check if this region is currently free RAM below 1MB */
710 if ((Descriptor
->Type
== BlConventionalMemory
) && (EndPage
<= 0x100))
712 /* Set an unknown flag on the descriptor */
713 Descriptor
->Flags
|= 0x80000;
716 /* Add the descriptor to the list, requesting coalescing as asked */
717 Status
= MmMdAddDescriptorToList(MemoryMap
,
719 BL_MM_ADD_DESCRIPTOR_TRUNCATE_FLAG
|
720 (Flags
& BL_MM_FLAG_REQUEST_COALESCING
) ?
721 BL_MM_ADD_DESCRIPTOR_COALESCE_FLAG
: 0);
722 if (!NT_SUCCESS(Status
))
724 EarlyPrint(L
"Failed to add full descriptor: %lx\n", Status
);
729 /* Consume this descriptor, and move to the next one */
730 EfiMemoryMapSize
-= DescriptorSize
;
731 EfiMemoryMap
= (PVOID
)((ULONG_PTR
)EfiMemoryMap
+ DescriptorSize
);
734 /* FIXME: @TODO: Mark the EfiBuffer as free, since we're about to free it */
735 /* For now, just "leak" the 1-2 pages... */
738 /* Free the EFI buffer, if we had one */
741 EfiFreePages(Pages
, EfiBuffer
);
744 /* On failure, free the memory map if one was passed in */
745 if (!NT_SUCCESS(Status
) && (MemoryMap
!= NULL
))
747 MmMdFreeList(MemoryMap
);
750 /* Decrement the nesting depth and return */
751 MmDescriptorCallTreeCount
--;
758 _In_ PBL_FIRMWARE_DESCRIPTOR FirmwareData
761 NTSTATUS Status
= STATUS_SUCCESS
;
762 EFI_KEY_TOGGLE_STATE KeyToggleState
;
764 /* Check if we have vaild firmware data */
765 if (!(FirmwareData
) || !(FirmwareData
->Version
))
767 return STATUS_INVALID_PARAMETER
;
770 /* Check which boot phase we're in */
773 /* Memory manager is ready, open the extended input protocol */
774 Status
= EfiOpenProtocol(EfiST
->ConsoleInHandle
,
775 &EfiSimpleTextInputExProtocol
,
776 (PVOID
*)&EfiConInEx
);
777 if (NT_SUCCESS(Status
))
779 /* Set the initial key toggle state */
780 KeyToggleState
= EFI_TOGGLE_STATE_VALID
| 40;
781 EfiConInExSetState(EfiConInEx
, &KeyToggleState
);
784 /* Setup the watchdog timer */
785 EfiSetWatchdogTimer();
789 /* Make a copy of the parameters */
790 EfiFirmwareParameters
= &EfiFirmwareData
;
792 /* Check which version we received */
793 if (FirmwareData
->Version
== 1)
795 /* FIXME: Not supported */
796 Status
= STATUS_NOT_SUPPORTED
;
798 else if (FirmwareData
->Version
>= 2)
800 /* Version 2 -- save the data */
801 EfiFirmwareData
= *FirmwareData
;
802 EfiSystemTable
= FirmwareData
->SystemTable
;
803 EfiImageHandle
= FirmwareData
->ImageHandle
;
805 /* Set the EDK-II style variables as well */
806 EfiST
= EfiSystemTable
;
807 EfiBS
= EfiSystemTable
->BootServices
;
808 EfiRT
= EfiSystemTable
->RuntimeServices
;
809 EfiConOut
= EfiSystemTable
->ConOut
;
810 EfiConIn
= EfiSystemTable
->ConIn
;
815 /* Unknown version */
816 Status
= STATUS_NOT_SUPPORTED
;
820 /* Return the initialization state */