diff --git a/Docs/Sample.plist b/Docs/Sample.plist index 89e1687c..dd65a40b 100644 --- a/Docs/Sample.plist +++ b/Docs/Sample.plist @@ -1322,6 +1322,7 @@ nvda_drv prev-lang:kbd backlight-level + BootCampHD 8BE4DF61-93CA-11D2-AA0D-00E098032B8C diff --git a/Docs/SampleCustom.plist b/Docs/SampleCustom.plist index 2f9670c3..5a9763dd 100644 --- a/Docs/SampleCustom.plist +++ b/Docs/SampleCustom.plist @@ -1349,6 +1349,7 @@ nvda_drv prev-lang:kbd backlight-level + BootCampHD 8BE4DF61-93CA-11D2-AA0D-00E098032B8C diff --git a/Include/Acidanthera/Library/OcBootManagementLib.h b/Include/Acidanthera/Library/OcBootManagementLib.h index 6c91c350..8632ad67 100644 --- a/Include/Acidanthera/Library/OcBootManagementLib.h +++ b/Include/Acidanthera/Library/OcBootManagementLib.h @@ -152,6 +152,7 @@ typedef UINT32 OC_BOOT_ENTRY_TYPE; #define OC_BOOT_EXTERNAL_OS BIT6 #define OC_BOOT_EXTERNAL_TOOL BIT7 #define OC_BOOT_SYSTEM BIT8 +#define OC_BOOT_EXTERNAL_SYSTEM BIT9 /** Picker mode. @@ -193,6 +194,26 @@ EFI_STATUS IN OUT OC_PICKER_CONTEXT *PickerContext ); +/** + Action to perform as part of executing an external boot system boot entry. +**/ +typedef +EFI_STATUS +(*OC_BOOT_EXTERNAL_SYSTEM_ACTION) ( + IN OUT OC_PICKER_CONTEXT *PickerContext, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ); + +/** + Gets Device Path for external boot system boot entry. +**/ +typedef +EFI_STATUS +(*OC_BOOT_EXTERNAL_SYSTEM_GET_DP) ( + IN OUT OC_PICKER_CONTEXT *PickerContext, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ); + /** Discovered boot entry. Note, inner resources must be freed with FreeBootEntry. @@ -201,103 +222,111 @@ typedef struct OC_BOOT_ENTRY_ { // // Link in entry list in OC_BOOT_FILESYSTEM. // - LIST_ENTRY Link; + LIST_ENTRY Link; // // Device path to booter or its directory. // Can be NULL, for example, for custom or system entries. // - EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; // // Action to perform on execution. Only valid for system entries. // - OC_BOOT_SYSTEM_ACTION SystemAction; + OC_BOOT_SYSTEM_ACTION SystemAction; + // + // Action to perform on execution. Only valid for external boot system entries. + // + OC_BOOT_EXTERNAL_SYSTEM_ACTION ExternalSystemAction; + // + // Gets Device Path for external boot system boot entry. Only valid for external boot system entries. + // + OC_BOOT_EXTERNAL_SYSTEM_GET_DP ExternalSystemGetDevicePath; // // Id under which to save entry as default. // - CHAR16 *Id; + CHAR16 *Id; // // Obtained human visible name. // - CHAR16 *Name; + CHAR16 *Name; // // Obtained boot path directory. // For custom entries this contains tool path. // - CHAR16 *PathName; + CHAR16 *PathName; // // Content flavour. // - CHAR8 *Flavour; + CHAR8 *Flavour; // // Heuristical value signaling inferred type of booted os. // WARNING: Non-definitive, do not rely on for any security purposes. // - OC_BOOT_ENTRY_TYPE Type; + OC_BOOT_ENTRY_TYPE Type; // // Entry index number, assigned by picker. // - UINT32 EntryIndex; + UINT32 EntryIndex; // // Set when this entry is an externally available entry (e.g. USB). // - BOOLEAN IsExternal; + BOOLEAN IsExternal; // // Should try booting from first dmg found in DevicePath. // - BOOLEAN IsFolder; + BOOLEAN IsFolder; // // Set when this entry refers to a generic booter (e.g. BOOTx64.EFI). // - BOOLEAN IsGeneric; + BOOLEAN IsGeneric; // // Set when this entry refers to a custom boot entry. // - BOOLEAN IsCustom; + BOOLEAN IsCustom; // // Set when entry was created by OC_BOOT_ENTRY_PROTOCOL. // - BOOLEAN IsBootEntryProtocol; + BOOLEAN IsBootEntryProtocol; // // Set when entry is identified as macOS installer. // - BOOLEAN IsAppleInstaller; + BOOLEAN IsAppleInstaller; // // Should make this option default boot option. // - BOOLEAN SetDefault; + BOOLEAN SetDefault; // // Should launch this entry in text mode. // - BOOLEAN LaunchInText; + BOOLEAN LaunchInText; // // Should expose real device path when dealing with custom entries. // - BOOLEAN ExposeDevicePath; + BOOLEAN ExposeDevicePath; // // Should disable OpenRuntime NVRAM protection around invocation of tool. // - BOOLEAN FullNvramAccess; + BOOLEAN FullNvramAccess; // // Partition UUID of entry device. // Set for non-system action boot entry protocol boot entries only. // - EFI_GUID UniquePartitionGUID; + EFI_GUID UniquePartitionGUID; // // Load option data (usually "boot args") size. // - UINT32 LoadOptionsSize; + UINT32 LoadOptionsSize; // // Load option data (usually "boot args"). // - VOID *LoadOptions; + VOID *LoadOptions; // // Audio base path for system action. Boot Entry Protocol only. // - CHAR8 *AudioBasePath; + CHAR8 *AudioBasePath; // // Audio base type for system action. Boot Entry Protocol only. // - CHAR8 *AudioBaseType; + CHAR8 *AudioBaseType; } OC_BOOT_ENTRY; /** @@ -557,56 +586,72 @@ typedef struct { // Multiple entries may share an id - allows e.g. newest version // of Linux install to automatically become selected default. // - CONST CHAR8 *Id; + CONST CHAR8 *Id; // // Entry name. // - CONST CHAR8 *Name; + CONST CHAR8 *Name; // // Absolute device path to file for user custom entries, // file path relative to device root for boot entry protocol. // - CONST CHAR8 *Path; + CONST CHAR8 *Path; // // Entry boot arguments. // - CONST CHAR8 *Arguments; + CONST CHAR8 *Arguments; // // Content flavour. // - CONST CHAR8 *Flavour; + CONST CHAR8 *Flavour; // // Whether this entry is auxiliary. // - BOOLEAN Auxiliary; + BOOLEAN Auxiliary; // // Whether this entry is a tool. // - BOOLEAN Tool; + BOOLEAN Tool; // // Whether it should be started in text mode. // - BOOLEAN TextMode; + BOOLEAN TextMode; // // Whether we should pass the actual device path (if possible). // - BOOLEAN RealPath; + BOOLEAN RealPath; // // Should disable OpenRuntime NVRAM protection around invocation of tool. // - BOOLEAN FullNvramAccess; + BOOLEAN FullNvramAccess; // // System action. Boot Entry Protocol only. Optional. // - OC_BOOT_SYSTEM_ACTION SystemAction; + OC_BOOT_SYSTEM_ACTION SystemAction; // // Audio base path for system action. Boot Entry Protocol only. Optional. // - CHAR8 *AudioBasePath; + CHAR8 *AudioBasePath; // // Audio base type for system action. Boot Entry Protocol only. Optional. // - CHAR8 *AudioBaseType; + CHAR8 *AudioBaseType; + // + // External boot system action. Boot Entry Protocol only. Optional. + // + OC_BOOT_EXTERNAL_SYSTEM_ACTION ExternalSystemAction; + // + // Gets Device Path for external boot system boot entry. Boot Entry Protocol only. Optional. + // + OC_BOOT_EXTERNAL_SYSTEM_GET_DP ExternalSystemGetDevicePath; + // + // External boot system Device Path. Boot Entry Protocol only. Optional. + // + EFI_DEVICE_PATH_PROTOCOL *ExternalSystemDevicePath; + // + // Whether this entry should be labeled as external to the system. Boot Entry Protocol only. Optional. + // + BOOLEAN External; } OC_PICKER_ENTRY; /** diff --git a/Include/Acidanthera/Library/OcFileLib.h b/Include/Acidanthera/Library/OcFileLib.h index 8846d6ea..4c45c643 100644 --- a/Include/Acidanthera/Library/OcFileLib.h +++ b/Include/Acidanthera/Library/OcFileLib.h @@ -19,6 +19,8 @@ #include +#include + #include #include #include @@ -482,6 +484,18 @@ OcOpenFileByDevicePath ( IN UINT64 Attributes ); +/** + Retrieve the disk's Device Path from a partition's Device Path. + + @param[in] HdDevicePath The Device Path of the partition. + + @retval Device Path or NULL +**/ +EFI_DEVICE_PATH_PROTOCOL * +OcDiskGetDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath + ); + /** Retrieve the disk's device handle from a partition's Device Path. @@ -494,6 +508,45 @@ OcPartitionGetDiskHandle ( IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath ); +/** + Retrieve the partition's device handle from a partition's Device Path. + + @param[in] HdDevicePath The Device Path of the partition. + +**/ +EFI_HANDLE +OcPartitionGetPartitionHandle ( + IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath + ); + +/** + Check if disk is a CD-ROM device. + + @param[in] DiskDevicePath The Device Path of the disk. + + @retval Device Path or NULL +**/ +BOOLEAN +OcIsDiskCdRom ( + IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath + ); + +/** + Read El-Torito boot sector from CD-ROM device. + + @param[in] DiskDevicePath The Device Path of the disk. + @param[out] Buffer Pointer to pool-allocated buffer containing the boot sector data. + @param[out] BufferSize Size of Buffer. + + @retval EFI_SUCCESS on success. +**/ +EFI_STATUS +OcDiskReadElTorito ( + IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath, + OUT UINT8 **Buffer, + OUT UINTN *BufferSize + ); + /** Locate the disk's EFI System Partition. @@ -554,6 +607,24 @@ OcDiskRead ( OUT VOID *Buffer ); +/** + Write information to disk. + + @param[in] Context Disk I/O context. + @param[in] Lba LBA number to write to. + @param[in] BufferSize Buffer size allocated in Buffer. + @param[out] Buffer Buffer containing data to write. + + @retval EFI_SUCCESS on success. +**/ +EFI_STATUS +OcDiskWrite ( + IN OC_DISK_CONTEXT *Context, + IN UINT64 Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ); + /** OC partition list. **/ @@ -590,6 +661,64 @@ OcGetGptPartitionEntry ( IN EFI_HANDLE FsHandle ); +/** + Retrieve the disk MBR table, if applicable. + + @param[in] DiskHandle Disk device handle to retrive MBR partition table from. + @param[in] CheckPartitions Check partition layout. This should be FALSE for a PBR. + + @retval MBR partition table or NULL. +**/ +MASTER_BOOT_RECORD * +OcGetDiskMbrTable ( + IN EFI_HANDLE DiskHandle, + IN BOOLEAN CheckPartitions + ); + +/** + Retrieve the MBR partition index for the specified partition. + + @param[in] PartitionHandle Partition device handle to retrieve MBR partition index for. + @param[out] PartitionIndex Pointer to store partition index in. + + @retval EFI_SUCCESS on success. +**/ +EFI_STATUS +OcDiskGetMbrPartitionIndex ( + IN EFI_HANDLE PartitionHandle, + OUT UINT8 *PartitionIndex + ); + +/** + Mark specified MBR partition as active. + + @param[in] DiskHandle Disk device handle containing MBR partition table + @param[in] PartitionIndex MBR partition index. + + @retval EFI_SUCCESS on success. +**/ +EFI_STATUS +OcDiskMarkMbrPartitionActive ( + IN EFI_HANDLE DiskHandle, + IN UINT8 PartitionIndex + ); + +/** + Locate the disk's active MBR partition. + + @param[in] DiskDevicePath The Device Path of the disk to scan. + @param[out] PartitionDevicePathSize The size of the returned Device Path. + @param[out] PartitionDeviceHandle Device handle of the returned partition. + + @return The device path protocol from the discovered handle or NULL. +**/ +EFI_DEVICE_PATH_PROTOCOL * +OcDiskFindActiveMbrPartitionPath ( + IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath, + OUT UINTN *PartitionDevicePathSize, + OUT EFI_HANDLE *PartitionDeviceHandle + ); + /** Creates a device path for a firmware file. diff --git a/Include/Acidanthera/Library/OcLegacyThunkLib.h b/Include/Acidanthera/Library/OcLegacyThunkLib.h new file mode 100644 index 00000000..0808cadb --- /dev/null +++ b/Include/Acidanthera/Library/OcLegacyThunkLib.h @@ -0,0 +1,91 @@ +/** @file + This library implements thunking to legacy 16-bit environment. + + Copyright (c) 2023, Goldfish64. All rights reserved.
+ Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause +**/ + +#ifndef OC_LEGACY_THUNK_LIB_H +#define OC_LEGACY_THUNK_LIB_H + +#include + +// +// Legacy region base is 0x0C0000. +// +#define LEGACY_REGION_BASE 0x0C0000 +#define LEGACY_REGION_SIZE 0x10000 + +#define EFI_SEGMENT(_Adr) (UINT16) ((UINT16) (((UINTN) (_Adr)) >> 4) & 0xf000) +#define EFI_OFFSET(_Adr) (UINT16) (((UINT16) ((UINTN) (_Adr))) & 0xffff) + +/** + Initialize legacy environment for BIOS INI caller. + + @param ThunkContext The instance pointer of THUNK_CONTEXT. +**/ +EFI_STATUS +OcLegacyThunkInitializeBiosIntCaller ( + IN OUT THUNK_CONTEXT *ThunkContext + ); + +/** + Initialize interrupt redirection code and entries, because + IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f. + Or the interrupt will lost when we do thunk. + NOTE: We do not reset 8259 vector base, because it will cause pending + interrupt lost. + + @param Legacy8259 Instance pointer for EFI_LEGACY_8259_PROTOCOL. + +**/ +EFI_STATUS +OcLegacyThunkInitializeInterruptRedirection ( + IN EFI_LEGACY_8259_PROTOCOL *Legacy8259 + ); + +/** + Disconnect all EFI graphics device handles in preparation for calling to legacy mode. +**/ +VOID +OcLegacyThunkDisconnectEfiGraphics ( + VOID + ); + +/** + Thunk to 16-bit real mode and execute a software interrupt with a vector + of BiosInt. Regs will contain the 16-bit register context on entry and + exit. + + @param ThunkContext The instance pointer of THUNK_CONTEXT. + @param Legacy8259 Instance pointer for EFI_LEGACY_8259_PROTOCOL. + @param BiosInt Processor interrupt vector to invoke + @param Reg Register contexted passed into (and returned) from thunk to 16-bit mode + + @retval TRUE Thunk completed, and there were no BIOS errors in the target code. + See Regs for status. + @retval FALSE There was a BIOS error in the target code. +**/ +BOOLEAN +EFIAPI +OcLegacyThunkBiosInt86 ( + IN THUNK_CONTEXT *ThunkContext, + IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, + IN UINT8 BiosInt, + IN IA32_REGISTER_SET *Regs + ); + +BOOLEAN +EFIAPI +OcLegacyThunkFarCall86 ( + IN THUNK_CONTEXT *ThunkContext, + IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, + IN UINT16 Segment, + IN UINT16 Offset, + IN IA32_REGISTER_SET *Regs, + IN VOID *Stack, + IN UINTN StackSize + ); + +#endif // OC_LEGACY_THUNK_LIB_H diff --git a/Include/Acidanthera/Protocol/OcBootEntry.h b/Include/Acidanthera/Protocol/OcBootEntry.h index 85c5bba6..9ac8326c 100644 --- a/Include/Acidanthera/Protocol/OcBootEntry.h +++ b/Include/Acidanthera/Protocol/OcBootEntry.h @@ -28,7 +28,7 @@ WARNING: This protocol is currently undergoing active design. **/ -#define OC_BOOT_ENTRY_PROTOCOL_REVISION 4 +#define OC_BOOT_ENTRY_PROTOCOL_REVISION 5 /** Forward declaration of OC_BOOT_ENTRY_PROTOCOL structure. diff --git a/Legacy/BootLoader/boot0.nasm b/Legacy/BootLoader/boot0.nasm index e9ca16e8..df88ec4c 100644 --- a/Legacy/BootLoader/boot0.nasm +++ b/Legacy/BootLoader/boot0.nasm @@ -90,8 +90,6 @@ kPartTypePMBR EQU 0xee ; On all GUID Partition Table disks a Pr ; reserving the entire space used on the disk by the GPT partitions, ; including all headers. -kPartActive EQU 0x80 ; active flag enabled -kPartInactive EQU 0x00 ; active flag disabled kEFISystemGUID EQU 0x3BC93EC9 ; last 4 bytes of EFI System Partition Type GUID: ; C12A7328-F81F-11D2-BA4B-00A0C93EC93B kBasicDataGUID EQU 0xC79926B7 ; last 4 bytes of Basic Data System Partition Type GUID: @@ -253,8 +251,7 @@ find_boot: .loop: ; - ; First scan through the partition table looking for the active - ; partition. + ; First scan through the partition table looking for the protective MBR. ; %if DEBUG mov al, [si + part.type] ; print partition type @@ -266,36 +263,18 @@ find_boot: cmp BYTE [si + part.type], 0 ; unused partition? je .continue ; skip to next entry cmp BYTE [si + part.type], kPartTypePMBR ; check for Protective MBR - jne .tryToBootIfActive - - mov BYTE [si + part.bootid], kPartInactive ; found Protective MBR - ; clear active flag to make sure this protective - ; partition won't be used as a bootable partition. - mov bl, 1 ; Assume we can deal with GPT but try to scan - ; later if not found any other bootable partitions. - -.tryToBootIfActive: - ; We're going to try to boot a partition if it is active - cmp BYTE [si + part.bootid], kPartActive jne .continue - ; - ; Found boot partition, read boot sector to memory. - ; - - xor dh, dh ; Argument for loadBootSector to skip file system signature check. - call loadBootSector - jne .continue - jmp SHORT initBootLoader + mov bl, 1 ; found Protective MBR + ; GPT header should be at LBA 1 .continue: add si, BYTE part_size ; advance SI to next partition entry loop .loop ; loop through all partition entries ; - ; Scanned all partitions but not found any with active flag enabled - ; Anyway if we found a protective MBR before we still have a chance - ; for a possible GPT Header at LBA 1 + ; Partition scan completed + ; If a protective MBR was found there should be a GPT header at LBA 1 ; dec bl jnz .exit ; didn't find Protective MBR before diff --git a/Legacy/BootPlatform/BiosVideo/BiosVideo.c b/Legacy/BootPlatform/BiosVideo/BiosVideo.c index f977eee1..1188832d 100644 --- a/Legacy/BootPlatform/BiosVideo/BiosVideo.c +++ b/Legacy/BootPlatform/BiosVideo/BiosVideo.c @@ -209,8 +209,15 @@ BiosVideoDriverBindingStart ( goto Done; } - InitializeBiosIntCaller (&mThunkContext); - InitializeInterruptRedirection (mLegacy8259); + Status = OcLegacyThunkInitializeBiosIntCaller (&mThunkContext); + if (EFI_ERROR (Status)) { + goto Done; + } + + Status = OcLegacyThunkInitializeInterruptRedirection (mLegacy8259); + if (EFI_ERROR (Status)) { + goto Done; + } } // @@ -622,12 +629,12 @@ BiosVideoChildHandleUninstall ( // Regs.H.AH = 0x00; Regs.H.AL = 0x03; - LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); + OcLegacyThunkBiosInt86 (BiosVideoPrivate->ThunkContext, BiosVideoPrivate->Legacy8259, 0x10, &Regs); Regs.H.AH = 0x11; Regs.H.AL = 0x14; Regs.H.BL = 0; - LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); + OcLegacyThunkBiosInt86 (BiosVideoPrivate->ThunkContext, BiosVideoPrivate->Legacy8259, 0x10, &Regs); // // Do not disable IO/memory decode since that would prevent legacy ROM from working @@ -712,7 +719,7 @@ BiosVideoGetVbeData ( Regs.E.ES = EFI_SEGMENT ((UINTN)BiosVideoPrivate->VbeInformationBlock); Regs.X.DI = EFI_OFFSET ((UINTN)BiosVideoPrivate->VbeInformationBlock); - LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); + OcLegacyThunkBiosInt86 (BiosVideoPrivate->ThunkContext, BiosVideoPrivate->Legacy8259, 0x10, &Regs); Status = EFI_DEVICE_ERROR; @@ -772,7 +779,7 @@ BiosVideoGetVbeData ( Regs.E.ES = EFI_SEGMENT ((UINTN)BiosVideoPrivate->VbeModeInformationBlock); Regs.X.DI = EFI_OFFSET ((UINTN)BiosVideoPrivate->VbeModeInformationBlock); - LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); + OcLegacyThunkBiosInt86 (BiosVideoPrivate->ThunkContext, BiosVideoPrivate->Legacy8259, 0x10, &Regs); // // See if the call succeeded. If it didn't, then try the next mode. @@ -984,7 +991,7 @@ BiosVideoGetVbeData ( Regs.E.ES = EFI_SEGMENT ((UINTN)BiosVideoPrivate->VbeEdidDataBlock); Regs.X.DI = EFI_OFFSET ((UINTN)BiosVideoPrivate->VbeEdidDataBlock); - LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); + OcLegacyThunkBiosInt86 (BiosVideoPrivate->ThunkContext, BiosVideoPrivate->Legacy8259, 0x10, &Regs); // // If the call succeed, populate EDID Discovered protocol. @@ -1533,7 +1540,7 @@ BiosVideoSetModeWorker ( // Set VGA Mode // Regs.X.AX = ModeData->VbeModeNumber; - LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); + OcLegacyThunkBiosInt86 (BiosVideoPrivate->ThunkContext, BiosVideoPrivate->Legacy8259, 0x10, &Regs); } else { // // Allocate a working buffer for BLT operations to the VBE frame buffer @@ -1554,7 +1561,7 @@ BiosVideoSetModeWorker ( Regs.E.ES = EFI_SEGMENT ((UINTN)BiosVideoPrivate->VbeCrtcInformationBlock); Regs.X.DI = EFI_OFFSET ((UINTN)BiosVideoPrivate->VbeCrtcInformationBlock); - LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); + OcLegacyThunkBiosInt86 (BiosVideoPrivate->ThunkContext, BiosVideoPrivate->Legacy8259, 0x10, &Regs); // // Check to see if the call succeeded @@ -2652,12 +2659,12 @@ BiosVideoVgaMiniPortSetMode ( // Regs.H.AH = 0x00; Regs.H.AL = 0x83; - LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); + OcLegacyThunkBiosInt86 (BiosVideoPrivate->ThunkContext, BiosVideoPrivate->Legacy8259, 0x10, &Regs); Regs.H.AH = 0x11; Regs.H.AL = 0x14; Regs.H.BL = 0; - LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); + OcLegacyThunkBiosInt86 (BiosVideoPrivate->ThunkContext, BiosVideoPrivate->Legacy8259, 0x10, &Regs); break; @@ -2667,12 +2674,12 @@ BiosVideoVgaMiniPortSetMode ( // Regs.H.AH = 0x00; Regs.H.AL = 0x83; - LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); + OcLegacyThunkBiosInt86 (BiosVideoPrivate->ThunkContext, BiosVideoPrivate->Legacy8259, 0x10, &Regs); Regs.H.AH = 0x11; Regs.H.AL = 0x12; Regs.H.BL = 0; - LegacyBiosInt86 (BiosVideoPrivate, 0x10, &Regs); + OcLegacyThunkBiosInt86 (BiosVideoPrivate->ThunkContext, BiosVideoPrivate->Legacy8259, 0x10, &Regs); break; default: diff --git a/Legacy/BootPlatform/BiosVideo/BiosVideo.h b/Legacy/BootPlatform/BiosVideo/BiosVideo.h index c6a88663..aec22985 100644 --- a/Legacy/BootPlatform/BiosVideo/BiosVideo.h +++ b/Legacy/BootPlatform/BiosVideo/BiosVideo.h @@ -47,6 +47,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include #include +#include #include #include @@ -55,13 +56,6 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. #include "VesaBiosExtensions.h" -// -// ** CHANGE ** -// Legacy region base is now 0x0C0000 instead of 0x100000. -// -#define LEGACY_REGION_BASE 0x0C0000 -#define LEGACY_REGION_SIZE 0x10000 - // // Vendor IDs. // @@ -171,9 +165,6 @@ typedef struct { #define GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER 0xffff -#define EFI_SEGMENT(_Adr) (UINT16) ((UINT16) (((UINTN) (_Adr)) >> 4) & 0xf000) -#define EFI_OFFSET(_Adr) (UINT16) (((UINT16) ((UINTN) (_Adr))) & 0xffff) - // // Global Variables // @@ -553,52 +544,6 @@ BiosVideoIsVga ( #define VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER 0x08 -/** - Initialize legacy environment for BIOS INI caller. - - @param ThunkContext the instance pointer of THUNK_CONTEXT -**/ -VOID -InitializeBiosIntCaller ( - THUNK_CONTEXT *ThunkContext - ); - -/** - Initialize interrupt redirection code and entries, because - IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f. - Or the interrupt will lost when we do thunk. - NOTE: We do not reset 8259 vector base, because it will cause pending - interrupt lost. - - @param Legacy8259 Instance pointer for EFI_LEGACY_8259_PROTOCOL. - -**/ -VOID -InitializeInterruptRedirection ( - IN EFI_LEGACY_8259_PROTOCOL *Legacy8259 - ); - -/** - Thunk to 16-bit real mode and execute a software interrupt with a vector - of BiosInt. Regs will contain the 16-bit register context on entry and - exit. - - @param This Protocol instance pointer. - @param BiosInt Processor interrupt vector to invoke - @param Reg Register contexted passed into (and returned) from thunk to 16-bit mode - - @retval TRUE Thunk completed, and there were no BIOS errors in the target code. - See Regs for status. - @retval FALSE There was a BIOS erro in the target code. -**/ -BOOLEAN -EFIAPI -LegacyBiosInt86 ( - IN BIOS_VIDEO_DEV *BiosDev, - IN UINT8 BiosInt, - IN IA32_REGISTER_SET *Regs - ); - /** Force the specified resolution and reconnect the controller. Specifying zero for Width and Height will pull the maximum diff --git a/Legacy/BootPlatform/BiosVideo/BiosVideo.inf b/Legacy/BootPlatform/BiosVideo/BiosVideo.inf index 23a88534..52ce22c6 100644 --- a/Legacy/BootPlatform/BiosVideo/BiosVideo.inf +++ b/Legacy/BootPlatform/BiosVideo/BiosVideo.inf @@ -37,6 +37,7 @@ MemoryAllocationLib UefiDriverEntryPoint DevicePathLib + OcLegacyThunkLib OcMemoryLib OcMiscLib @@ -45,7 +46,6 @@ BiosVideo.c ComponentName.c VesaBiosExtensions.h - LegacyBiosThunk.c VideoBiosPatch.c [Protocols] diff --git a/Legacy/BootPlatform/BiosVideo/LegacyBiosThunk.c b/Legacy/BootPlatform/BiosVideo/LegacyBiosThunk.c deleted file mode 100644 index 67ae8836..00000000 --- a/Legacy/BootPlatform/BiosVideo/LegacyBiosThunk.c +++ /dev/null @@ -1,218 +0,0 @@ -/** @file - Provide legacy thunk interface for accessing Bios Video Rom. - -Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "BiosVideo.h" - -/** - Initialize legacy environment for BIOS INI caller. - - @param ThunkContext the instance pointer of THUNK_CONTEXT -**/ -VOID -InitializeBiosIntCaller ( - THUNK_CONTEXT *ThunkContext - ) -{ - EFI_STATUS Status; - UINT32 RealModeBufferSize; - UINT32 ExtraStackSize; - EFI_PHYSICAL_ADDRESS LegacyRegionBase; - UINT32 LegacyRegionSize; - - // - // Get LegacyRegion - // - AsmGetThunk16Properties (&RealModeBufferSize, &ExtraStackSize); - LegacyRegionSize = (((RealModeBufferSize + ExtraStackSize) / EFI_PAGE_SIZE) + 1) * EFI_PAGE_SIZE; - LegacyRegionBase = LEGACY_REGION_BASE; - Status = gBS->AllocatePages ( - AllocateMaxAddress, - EfiACPIMemoryNVS, - EFI_SIZE_TO_PAGES (LegacyRegionSize), - &LegacyRegionBase - ); - ASSERT_EFI_ERROR (Status); - - ZeroMem ((VOID *)(UINTN)LegacyRegionBase, LegacyRegionSize); - - ThunkContext->RealModeBuffer = (VOID *)(UINTN)LegacyRegionBase; - ThunkContext->RealModeBufferSize = LegacyRegionSize; - ThunkContext->ThunkAttributes = THUNK_ATTRIBUTE_BIG_REAL_MODE|THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15; - AsmPrepareThunk16 (ThunkContext); -} - -/** - Initialize interrupt redirection code and entries, because - IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f. - Or the interrupt will lost when we do thunk. - NOTE: We do not reset 8259 vector base, because it will cause pending - interrupt lost. - - @param Legacy8259 Instance pointer for EFI_LEGACY_8259_PROTOCOL. - -**/ -VOID -InitializeInterruptRedirection ( - IN EFI_LEGACY_8259_PROTOCOL *Legacy8259 - ) -{ - EFI_STATUS Status; - EFI_PHYSICAL_ADDRESS LegacyRegionBase; - UINTN LegacyRegionLength; - volatile UINT32 *IdtArray; - UINTN Index; - UINT8 ProtectedModeBaseVector; - - STATIC CONST UINT32 InterruptRedirectionCode[] = { - 0x90CF08CD, // INT8; IRET; NOP - 0x90CF09CD, // INT9; IRET; NOP - 0x90CF0ACD, // INTA; IRET; NOP - 0x90CF0BCD, // INTB; IRET; NOP - 0x90CF0CCD, // INTC; IRET; NOP - 0x90CF0DCD, // INTD; IRET; NOP - 0x90CF0ECD, // INTE; IRET; NOP - 0x90CF0FCD // INTF; IRET; NOP - }; - - // - // Get LegacyRegion - // - LegacyRegionLength = sizeof (InterruptRedirectionCode); - LegacyRegionBase = LEGACY_REGION_BASE; - Status = gBS->AllocatePages ( - AllocateMaxAddress, - EfiACPIMemoryNVS, - EFI_SIZE_TO_PAGES (LegacyRegionLength), - &LegacyRegionBase - ); - ASSERT_EFI_ERROR (Status); - - // - // Copy code to legacy region - // - CopyMem ((VOID *)(UINTN)LegacyRegionBase, InterruptRedirectionCode, sizeof (InterruptRedirectionCode)); - - // - // Get VectorBase, it should be 0x68 - // - Status = Legacy8259->GetVector (Legacy8259, Efi8259Irq0, &ProtectedModeBaseVector); - ASSERT_EFI_ERROR (Status); - - // - // Patch IVT 0x68 ~ 0x6f - // - IdtArray = (UINT32 *)0; - for (Index = 0; Index < 8; Index++) { - IdtArray[ProtectedModeBaseVector + Index] = ((EFI_SEGMENT (LegacyRegionBase + Index * 4)) << 16) | (EFI_OFFSET (LegacyRegionBase + Index * 4)); - } -} - -/** - Thunk to 16-bit real mode and execute a software interrupt with a vector - of BiosInt. Regs will contain the 16-bit register context on entry and - exit. - - @param This Protocol instance pointer. - @param BiosInt Processor interrupt vector to invoke - @param Reg Register contexted passed into (and returned) from thunk to 16-bit mode - - @retval TRUE Thunk completed, and there were no BIOS errors in the target code. - See Regs for status. - @retval FALSE There was a BIOS erro in the target code. -**/ -BOOLEAN -EFIAPI -LegacyBiosInt86 ( - IN BIOS_VIDEO_DEV *BiosDev, - IN UINT8 BiosInt, - IN IA32_REGISTER_SET *Regs - ) -{ - UINTN Status; - IA32_REGISTER_SET ThunkRegSet; - BOOLEAN Ret; - UINT16 *Stack16; - BOOLEAN Enabled; - - ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet)); - ThunkRegSet.E.EFLAGS.Bits.Reserved_0 = 1; - ThunkRegSet.E.EFLAGS.Bits.Reserved_1 = 0; - ThunkRegSet.E.EFLAGS.Bits.Reserved_2 = 0; - ThunkRegSet.E.EFLAGS.Bits.Reserved_3 = 0; - ThunkRegSet.E.EFLAGS.Bits.IOPL = 3; - ThunkRegSet.E.EFLAGS.Bits.NT = 0; - ThunkRegSet.E.EFLAGS.Bits.IF = 1; - ThunkRegSet.E.EFLAGS.Bits.TF = 0; - ThunkRegSet.E.EFLAGS.Bits.CF = 0; - - ThunkRegSet.E.EDI = Regs->E.EDI; - ThunkRegSet.E.ESI = Regs->E.ESI; - ThunkRegSet.E.EBP = Regs->E.EBP; - ThunkRegSet.E.EBX = Regs->E.EBX; - ThunkRegSet.E.EDX = Regs->E.EDX; - ThunkRegSet.E.ECX = Regs->E.ECX; - ThunkRegSet.E.EAX = Regs->E.EAX; - ThunkRegSet.E.DS = Regs->E.DS; - ThunkRegSet.E.ES = Regs->E.ES; - - // - // The call to Legacy16 is a critical section to EFI - // - Enabled = SaveAndDisableInterrupts (); - - // - // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases. - // - Status = BiosDev->Legacy8259->SetMode (BiosDev->Legacy8259, Efi8259LegacyMode, NULL, NULL); - ASSERT_EFI_ERROR (Status); - - Stack16 = (UINT16 *)((UINT8 *)BiosDev->ThunkContext->RealModeBuffer + BiosDev->ThunkContext->RealModeBufferSize - sizeof (UINT16)); - - ThunkRegSet.E.SS = (UINT16)(((UINTN)Stack16 >> 16) << 12); - ThunkRegSet.E.ESP = (UINT16)(UINTN)Stack16; - - ThunkRegSet.E.Eip = (UINT16)((volatile UINT32 *)NULL)[BiosInt]; - ThunkRegSet.E.CS = (UINT16)(((volatile UINT32 *)NULL)[BiosInt] >> 16); - BiosDev->ThunkContext->RealModeState = &ThunkRegSet; - AsmThunk16 (BiosDev->ThunkContext); - - // - // Restore protected mode interrupt state - // - Status = BiosDev->Legacy8259->SetMode (BiosDev->Legacy8259, Efi8259ProtectedMode, NULL, NULL); - ASSERT_EFI_ERROR (Status); - - // - // End critical section - // - SetInterruptState (Enabled); - - Regs->E.EDI = ThunkRegSet.E.EDI; - Regs->E.ESI = ThunkRegSet.E.ESI; - Regs->E.EBP = ThunkRegSet.E.EBP; - Regs->E.EBX = ThunkRegSet.E.EBX; - Regs->E.EDX = ThunkRegSet.E.EDX; - Regs->E.ECX = ThunkRegSet.E.ECX; - Regs->E.EAX = ThunkRegSet.E.EAX; - Regs->E.SS = ThunkRegSet.E.SS; - Regs->E.CS = ThunkRegSet.E.CS; - Regs->E.DS = ThunkRegSet.E.DS; - Regs->E.ES = ThunkRegSet.E.ES; - - CopyMem (&(Regs->E.EFLAGS), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32)); - - Ret = (BOOLEAN)(Regs->E.EFLAGS.Bits.CF == 1); - - return Ret; -} diff --git a/Legacy/BootPlatform/BlockIoDxe/BiosBlkIo.c b/Legacy/BootPlatform/BlockIoDxe/BiosBlkIo.c index 5daecf12..10ca63a2 100644 --- a/Legacy/BootPlatform/BlockIoDxe/BiosBlkIo.c +++ b/Legacy/BootPlatform/BlockIoDxe/BiosBlkIo.c @@ -255,8 +255,15 @@ BiosBlockIoDriverBindingStart ( goto Error; } - InitializeBiosIntCaller (&mThunkContext); - InitializeInterruptRedirection (Legacy8259); + Status = OcLegacyThunkInitializeBiosIntCaller (&mThunkContext); + if (EFI_ERROR (Status)) { + goto Error; + } + + Status = OcLegacyThunkInitializeInterruptRedirection (Legacy8259); + if (EFI_ERROR (Status)) { + goto Error; + } // // Open the IO Abstraction(s) needed diff --git a/Legacy/BootPlatform/BlockIoDxe/BiosBlkIo.h b/Legacy/BootPlatform/BlockIoDxe/BiosBlkIo.h index b8bb04ea..c971e597 100644 --- a/Legacy/BootPlatform/BlockIoDxe/BiosBlkIo.h +++ b/Legacy/BootPlatform/BlockIoDxe/BiosBlkIo.h @@ -26,13 +26,12 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #include #include #include +#include #include #include "Edd.h" -#define LEGACY_REGION_BASE 0x0C0000 - // // Global Variables // @@ -423,50 +422,4 @@ SetBiosInitBlockIoDevicePath ( OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath ); -/** - Initialize legacy environment for BIOS INI caller. - - @param ThunkContext the instance pointer of THUNK_CONTEXT -**/ -VOID -InitializeBiosIntCaller ( - THUNK_CONTEXT *ThunkContext - ); - -/** - Initialize interrupt redirection code and entries, because - IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f. - Or the interrupt will lost when we do thunk. - NOTE: We do not reset 8259 vector base, because it will cause pending - interrupt lost. - - @param Legacy8259 Instance pointer for EFI_LEGACY_8259_PROTOCOL. - -**/ -VOID -InitializeInterruptRedirection ( - IN EFI_LEGACY_8259_PROTOCOL *Legacy8259 - ); - -/** - Thunk to 16-bit real mode and execute a software interrupt with a vector - of BiosInt. Regs will contain the 16-bit register context on entry and - exit. - - @param This Protocol instance pointer. - @param BiosInt Processor interrupt vector to invoke - @param Reg Register contexted passed into (and returned) from thunk to 16-bit mode - - @retval TRUE Thunk completed, and there were no BIOS errors in the target code. - See Regs for status. - @retval FALSE There was a BIOS erro in the target code. -**/ -BOOLEAN -EFIAPI -LegacyBiosInt86 ( - IN BIOS_BLOCK_IO_DEV *BiosDev, - IN UINT8 BiosInt, - IN IA32_REGISTER_SET *Regs - ); - #endif diff --git a/Legacy/BootPlatform/BlockIoDxe/BiosInt13.c b/Legacy/BootPlatform/BlockIoDxe/BiosInt13.c index 7b8c8765..d6c0c686 100644 --- a/Legacy/BootPlatform/BlockIoDxe/BiosInt13.c +++ b/Legacy/BootPlatform/BlockIoDxe/BiosInt13.c @@ -137,7 +137,7 @@ Int13GetDeviceParameters ( Regs.H.AH = 0x08; Regs.H.DL = Drive->Number; - CarryFlag = LegacyBiosInt86 (BiosBlockIoDev, 0x13, &Regs); + CarryFlag = OcLegacyThunkBiosInt86 (BiosBlockIoDev->ThunkContext, BiosBlockIoDev->Legacy8259, 0x13, &Regs); DEBUG ((DEBUG_INIT, "Int13GetDeviceParameters: INT 13 08 DL=%02x : CF=%d AH=%02x\n", Drive->Number, CarryFlag, Regs.H.AH)); if ((CarryFlag != 0) || (Regs.H.AH != 0x00)) { Drive->ErrorCode = Regs.H.AH; @@ -192,7 +192,7 @@ Int13Extensions ( Regs.H.AH = 0x41; Regs.X.BX = 0x55aa; Regs.H.DL = Drive->Number; - CarryFlag = LegacyBiosInt86 (BiosBlockIoDev, 0x13, &Regs); + CarryFlag = OcLegacyThunkBiosInt86 (BiosBlockIoDev->ThunkContext, BiosBlockIoDev->Legacy8259, 0x13, &Regs); DEBUG ((DEBUG_INIT, "Int13Extensions: INT 13 41 DL=%02x : CF=%d BX=%04x\n", Drive->Number, CarryFlag, Regs.X.BX)); if ((CarryFlag != 0) || (Regs.X.BX != 0xaa55)) { @@ -242,7 +242,7 @@ GetDriveParameters ( mLegacyDriverUnder1Mb->Parameters.StructureSize = (UINT16)sizeof (EDD_DRIVE_PARAMETERS); Regs.E.DS = EFI_SEGMENT ((UINTN)(&mLegacyDriverUnder1Mb->Parameters)); Regs.X.SI = EFI_OFFSET ((UINTN)(&mLegacyDriverUnder1Mb->Parameters)); - CarryFlag = LegacyBiosInt86 (BiosBlockIoDev, 0x13, &Regs); + CarryFlag = OcLegacyThunkBiosInt86 (BiosBlockIoDev->ThunkContext, BiosBlockIoDev->Legacy8259, 0x13, &Regs); DEBUG ((DEBUG_INIT, "GetDriveParameters: INT 13 48 DL=%02x : CF=%d AH=%02x\n", Drive->Number, CarryFlag, Regs.H.AH)); if ((CarryFlag != 0) || (Regs.H.AH != 0x00)) { Drive->ErrorCode = Regs.H.AH; @@ -265,7 +265,7 @@ GetDriveParameters ( // Regs.H.AH = 0x20; Regs.H.DL = Drive->Number; - CarryFlag = LegacyBiosInt86 (BiosBlockIoDev, 0x13, &Regs); + CarryFlag = OcLegacyThunkBiosInt86 (BiosBlockIoDev->ThunkContext, BiosBlockIoDev->Legacy8259, 0x13, &Regs); DEBUG ((DEBUG_INIT, "GetDriveParameters: INT 13 20 DL=%02x : CF=%d AL=%02x\n", Drive->Number, CarryFlag, Regs.H.AL)); if (CarryFlag != 0) { // @@ -482,7 +482,7 @@ Edd30BiosReadBlocks ( Regs.X.SI = EFI_OFFSET (AddressPacket); Regs.E.DS = EFI_SEGMENT (AddressPacket); - CarryFlag = LegacyBiosInt86 (BiosBlockIoDev, 0x13, &Regs); + CarryFlag = OcLegacyThunkBiosInt86 (BiosBlockIoDev->ThunkContext, BiosBlockIoDev->Legacy8259, 0x13, &Regs); DEBUG ( ( DEBUG_BLKIO, "Edd30BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, @@ -631,7 +631,7 @@ Edd30BiosWriteBlocks ( Regs.X.SI = EFI_OFFSET (AddressPacket); Regs.E.DS = EFI_SEGMENT (AddressPacket); - CarryFlag = LegacyBiosInt86 (BiosBlockIoDev, 0x13, &Regs); + CarryFlag = OcLegacyThunkBiosInt86 (BiosBlockIoDev->ThunkContext, BiosBlockIoDev->Legacy8259, 0x13, &Regs); DEBUG ( ( DEBUG_BLKIO, "Edd30BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, @@ -730,7 +730,7 @@ BiosBlockIoReset ( Regs.H.AH = 0x00; Regs.H.DL = BiosBlockIoDev->Bios.Number; - CarryFlag = LegacyBiosInt86 (BiosBlockIoDev, 0x13, &Regs); + CarryFlag = OcLegacyThunkBiosInt86 (BiosBlockIoDev->ThunkContext, BiosBlockIoDev->Legacy8259, 0x13, &Regs); DEBUG ( ( DEBUG_INIT, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, CarryFlag, @@ -742,7 +742,7 @@ BiosBlockIoReset ( if (Regs.H.AL == BIOS_RESET_FAILED) { Regs.H.AH = 0x00; Regs.H.DL = BiosBlockIoDev->Bios.Number; - CarryFlag = LegacyBiosInt86 (BiosBlockIoDev, 0x13, &Regs); + CarryFlag = OcLegacyThunkBiosInt86 (BiosBlockIoDev->ThunkContext, BiosBlockIoDev->Legacy8259, 0x13, &Regs); DEBUG ( ( DEBUG_INIT, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, CarryFlag, @@ -867,7 +867,7 @@ Edd11BiosReadBlocks ( Regs.X.SI = EFI_OFFSET (AddressPacket); Regs.E.DS = EFI_SEGMENT (AddressPacket); - CarryFlag = LegacyBiosInt86 (BiosBlockIoDev, 0x13, &Regs); + CarryFlag = OcLegacyThunkBiosInt86 (BiosBlockIoDev->ThunkContext, BiosBlockIoDev->Legacy8259, 0x13, &Regs); DEBUG ( ( DEBUG_BLKIO, "Edd11BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x : LBA 0x%lx Block(s) %0d \n", @@ -1025,7 +1025,7 @@ Edd11BiosWriteBlocks ( TransferByteSize = NumberOfBlocks * BlockSize; CopyMem ((VOID *)(UINTN)TransferBuffer, Buffer, TransferByteSize); - CarryFlag = LegacyBiosInt86 (BiosBlockIoDev, 0x13, &Regs); + CarryFlag = OcLegacyThunkBiosInt86 (BiosBlockIoDev->ThunkContext, BiosBlockIoDev->Legacy8259, 0x13, &Regs); DEBUG ( ( DEBUG_BLKIO, "Edd11BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n: LBA 0x%lx Block(s) %0d \n", @@ -1217,7 +1217,7 @@ BiosReadLegacyDrive ( EFI_SEGMENT (mEdd11Buffer)) ); - CarryFlag = LegacyBiosInt86 (BiosBlockIoDev, 0x13, &Regs); + CarryFlag = OcLegacyThunkBiosInt86 (BiosBlockIoDev->ThunkContext, BiosBlockIoDev->Legacy8259, 0x13, &Regs); DEBUG ( ( DEBUG_BLKIO, "BiosReadLegacyDrive: INT 13 02 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, @@ -1422,7 +1422,7 @@ BiosWriteLegacyDrive ( EFI_SEGMENT (mEdd11Buffer)) ); - CarryFlag = LegacyBiosInt86 (BiosBlockIoDev, 0x13, &Regs); + CarryFlag = OcLegacyThunkBiosInt86 (BiosBlockIoDev->ThunkContext, BiosBlockIoDev->Legacy8259, 0x13, &Regs); DEBUG ( ( DEBUG_BLKIO, "BiosWriteLegacyDrive: INT 13 03 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, diff --git a/Legacy/BootPlatform/BlockIoDxe/BlockIoDxe.inf b/Legacy/BootPlatform/BlockIoDxe/BlockIoDxe.inf index f02cd734..7a732a93 100644 --- a/Legacy/BootPlatform/BlockIoDxe/BlockIoDxe.inf +++ b/Legacy/BootPlatform/BlockIoDxe/BlockIoDxe.inf @@ -26,7 +26,6 @@ BiosBlkIo.c BiosInt13.c ComponentName.c - LegacyBiosThunk.c [LibraryClasses] UefiDriverEntryPoint @@ -36,6 +35,7 @@ UefiLib DevicePathLib MemoryAllocationLib + OcLegacyThunkLib [Protocols] gEfiBlockIoProtocolGuid ## BY_START diff --git a/Legacy/BootPlatform/BlockIoDxe/LegacyBiosThunk.c b/Legacy/BootPlatform/BlockIoDxe/LegacyBiosThunk.c deleted file mode 100644 index e0e426a7..00000000 --- a/Legacy/BootPlatform/BlockIoDxe/LegacyBiosThunk.c +++ /dev/null @@ -1,216 +0,0 @@ -/** @file - Provide legacy thunk interface for accessing Bios Block I/O. - -Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. - -**/ - -#include "BiosBlkIo.h" - -/** - Initialize legacy environment for BIOS INI caller. - - @param ThunkContext the instance pointer of THUNK_CONTEXT -**/ -VOID -InitializeBiosIntCaller ( - THUNK_CONTEXT *ThunkContext - ) -{ - EFI_STATUS Status; - UINT32 RealModeBufferSize; - UINT32 ExtraStackSize; - EFI_PHYSICAL_ADDRESS LegacyRegionBase; - UINT32 LegacyRegionSize; - - // - // Get LegacyRegion - // - AsmGetThunk16Properties (&RealModeBufferSize, &ExtraStackSize); - LegacyRegionSize = (((RealModeBufferSize + ExtraStackSize) / EFI_PAGE_SIZE) + 1) * EFI_PAGE_SIZE; - LegacyRegionBase = LEGACY_REGION_BASE; - Status = gBS->AllocatePages ( - AllocateMaxAddress, - EfiACPIMemoryNVS, - EFI_SIZE_TO_PAGES (LegacyRegionSize), - &LegacyRegionBase - ); - ASSERT_EFI_ERROR (Status); - - ThunkContext->RealModeBuffer = (VOID *)(UINTN)LegacyRegionBase; - ThunkContext->RealModeBufferSize = LegacyRegionSize; - ThunkContext->ThunkAttributes = THUNK_ATTRIBUTE_BIG_REAL_MODE|THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15; - AsmPrepareThunk16 (ThunkContext); -} - -/** - Initialize interrupt redirection code and entries, because - IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f. - Or the interrupt will lost when we do thunk. - NOTE: We do not reset 8259 vector base, because it will cause pending - interrupt lost. - - @param Legacy8259 Instance pointer for EFI_LEGACY_8259_PROTOCOL. - -**/ -VOID -InitializeInterruptRedirection ( - IN EFI_LEGACY_8259_PROTOCOL *Legacy8259 - ) -{ - EFI_STATUS Status; - EFI_PHYSICAL_ADDRESS LegacyRegionBase; - UINTN LegacyRegionLength; - volatile UINT32 *IdtArray; - UINTN Index; - UINT8 ProtectedModeBaseVector; - - STATIC CONST UINT32 InterruptRedirectionCode[] = { - 0x90CF08CD, // INT8; IRET; NOP - 0x90CF09CD, // INT9; IRET; NOP - 0x90CF0ACD, // INTA; IRET; NOP - 0x90CF0BCD, // INTB; IRET; NOP - 0x90CF0CCD, // INTC; IRET; NOP - 0x90CF0DCD, // INTD; IRET; NOP - 0x90CF0ECD, // INTE; IRET; NOP - 0x90CF0FCD // INTF; IRET; NOP - }; - - // - // Get LegacyRegion - // - LegacyRegionLength = sizeof (InterruptRedirectionCode); - LegacyRegionBase = LEGACY_REGION_BASE; - Status = gBS->AllocatePages ( - AllocateMaxAddress, - EfiACPIMemoryNVS, - EFI_SIZE_TO_PAGES (LegacyRegionLength), - &LegacyRegionBase - ); - ASSERT_EFI_ERROR (Status); - - // - // Copy code to legacy region - // - CopyMem ((VOID *)(UINTN)LegacyRegionBase, InterruptRedirectionCode, sizeof (InterruptRedirectionCode)); - - // - // Get VectorBase, it should be 0x68 - // - Status = Legacy8259->GetVector (Legacy8259, Efi8259Irq0, &ProtectedModeBaseVector); - ASSERT_EFI_ERROR (Status); - - // - // Patch IVT 0x68 ~ 0x6f - // - IdtArray = (UINT32 *)0; - for (Index = 0; Index < 8; Index++) { - IdtArray[ProtectedModeBaseVector + Index] = ((EFI_SEGMENT (LegacyRegionBase + Index * 4)) << 16) | (EFI_OFFSET (LegacyRegionBase + Index * 4)); - } -} - -/** - Thunk to 16-bit real mode and execute a software interrupt with a vector - of BiosInt. Regs will contain the 16-bit register context on entry and - exit. - - @param This Protocol instance pointer. - @param BiosInt Processor interrupt vector to invoke - @param Reg Register contexted passed into (and returned) from thunk to 16-bit mode - - @retval TRUE Thunk completed, and there were no BIOS errors in the target code. - See Regs for status. - @retval FALSE There was a BIOS erro in the target code. -**/ -BOOLEAN -EFIAPI -LegacyBiosInt86 ( - IN BIOS_BLOCK_IO_DEV *BiosDev, - IN UINT8 BiosInt, - IN IA32_REGISTER_SET *Regs - ) -{ - UINTN Status; - IA32_REGISTER_SET ThunkRegSet; - BOOLEAN Ret; - UINT16 *Stack16; - BOOLEAN Enabled; - - ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet)); - ThunkRegSet.E.EFLAGS.Bits.Reserved_0 = 1; - ThunkRegSet.E.EFLAGS.Bits.Reserved_1 = 0; - ThunkRegSet.E.EFLAGS.Bits.Reserved_2 = 0; - ThunkRegSet.E.EFLAGS.Bits.Reserved_3 = 0; - ThunkRegSet.E.EFLAGS.Bits.IOPL = 3; - ThunkRegSet.E.EFLAGS.Bits.NT = 0; - ThunkRegSet.E.EFLAGS.Bits.IF = 1; - ThunkRegSet.E.EFLAGS.Bits.TF = 0; - ThunkRegSet.E.EFLAGS.Bits.CF = 0; - - ThunkRegSet.E.EDI = Regs->E.EDI; - ThunkRegSet.E.ESI = Regs->E.ESI; - ThunkRegSet.E.EBP = Regs->E.EBP; - ThunkRegSet.E.EBX = Regs->E.EBX; - ThunkRegSet.E.EDX = Regs->E.EDX; - ThunkRegSet.E.ECX = Regs->E.ECX; - ThunkRegSet.E.EAX = Regs->E.EAX; - ThunkRegSet.E.DS = Regs->E.DS; - ThunkRegSet.E.ES = Regs->E.ES; - - // - // The call to Legacy16 is a critical section to EFI - // - Enabled = SaveAndDisableInterrupts (); - - // - // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases. - // - Status = BiosDev->Legacy8259->SetMode (BiosDev->Legacy8259, Efi8259LegacyMode, NULL, NULL); - ASSERT_EFI_ERROR (Status); - - Stack16 = (UINT16 *)((UINT8 *)BiosDev->ThunkContext->RealModeBuffer + BiosDev->ThunkContext->RealModeBufferSize - sizeof (UINT16)); - - ThunkRegSet.E.SS = (UINT16)(((UINTN)Stack16 >> 16) << 12); - ThunkRegSet.E.ESP = (UINT16)(UINTN)Stack16; - - ThunkRegSet.E.Eip = (UINT16)((volatile UINT32 *)NULL)[BiosInt]; - ThunkRegSet.E.CS = (UINT16)(((volatile UINT32 *)NULL)[BiosInt] >> 16); - BiosDev->ThunkContext->RealModeState = &ThunkRegSet; - AsmThunk16 (BiosDev->ThunkContext); - - // - // Restore protected mode interrupt state - // - Status = BiosDev->Legacy8259->SetMode (BiosDev->Legacy8259, Efi8259ProtectedMode, NULL, NULL); - ASSERT_EFI_ERROR (Status); - - // - // End critical section - // - SetInterruptState (Enabled); - - Regs->E.EDI = ThunkRegSet.E.EDI; - Regs->E.ESI = ThunkRegSet.E.ESI; - Regs->E.EBP = ThunkRegSet.E.EBP; - Regs->E.EBX = ThunkRegSet.E.EBX; - Regs->E.EDX = ThunkRegSet.E.EDX; - Regs->E.ECX = ThunkRegSet.E.ECX; - Regs->E.EAX = ThunkRegSet.E.EAX; - Regs->E.SS = ThunkRegSet.E.SS; - Regs->E.CS = ThunkRegSet.E.CS; - Regs->E.DS = ThunkRegSet.E.DS; - Regs->E.ES = ThunkRegSet.E.ES; - - CopyMem (&(Regs->E.EFLAGS), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32)); - - Ret = (BOOLEAN)(Regs->E.EFLAGS.Bits.CF == 1); - - return Ret; -} diff --git a/Legacy/BootPlatform/CpuDxe/CpuDxe.c b/Legacy/BootPlatform/CpuDxe/CpuDxe.c index 6b20f143..8d900be4 100644 --- a/Legacy/BootPlatform/CpuDxe/CpuDxe.c +++ b/Legacy/BootPlatform/CpuDxe/CpuDxe.c @@ -948,8 +948,8 @@ Return --*/ { - EFI_IA32_REGISTER_SET Regs; - UINT16 OriginalVideoMode = (UINT16)-1; + IA32_REGISTER_SET Regs; + UINT16 OriginalVideoMode = (UINT16)-1; // // Set new video mode @@ -970,7 +970,7 @@ Return gBS->SetMem (&Regs, sizeof (Regs), 0); Regs.H.AH = 0x00; Regs.H.AL = (UINT8)NewVideoMode; - LegacyBiosInt86 (0x10, &Regs); + OcLegacyThunkBiosInt86 (&mThunkContext, gLegacy8259, 0x10, &Regs); // // VIDEO - TEXT-MODE CHARGEN - LOAD ROM 8x16 CHARACTER SET (VGA) @@ -982,7 +982,7 @@ Return Regs.H.AH = 0x11; Regs.H.AL = 0x14; Regs.H.BL = 0; - LegacyBiosInt86 (0x10, &Regs); + OcLegacyThunkBiosInt86 (&mThunkContext, gLegacy8259, 0x10, &Regs); } else { // // VESA SuperVGA BIOS - SET SuperVGA VIDEO MODE @@ -998,7 +998,7 @@ Return gBS->SetMem (&Regs, sizeof (Regs), 0); Regs.X.AX = 0x4F02; Regs.X.BX = NewVideoMode; - LegacyBiosInt86 (0x10, &Regs); + OcLegacyThunkBiosInt86 (&mThunkContext, gLegacy8259, 0x10, &Regs); if (Regs.X.AX != 0x004F) { // // SORRY: Cannot set to video mode! @@ -1138,7 +1138,8 @@ Returns: InstallInterruptHandler (InterruptVector, SystemTimerHandler); } - InitializeBiosIntCaller (); + Status = OcLegacyThunkInitializeBiosIntCaller (&mThunkContext); + ASSERT_EFI_ERROR (Status); // // Install CPU Architectural Protocol and the thunk protocol @@ -1153,129 +1154,3 @@ Returns: ASSERT_EFI_ERROR (Status); return Status; } - -VOID -InitializeBiosIntCaller ( - VOID - ) -{ - EFI_STATUS Status; - UINT32 RealModeBufferSize; - UINT32 ExtraStackSize; - EFI_PHYSICAL_ADDRESS LegacyRegionBase; - UINT32 LegacyRegionSize; - - // - // Get LegacyRegion - // - AsmGetThunk16Properties (&RealModeBufferSize, &ExtraStackSize); - LegacyRegionSize = (((RealModeBufferSize + ExtraStackSize) / EFI_PAGE_SIZE) + 1) * EFI_PAGE_SIZE; - LegacyRegionBase = 0x0C0000; - Status = gBS->AllocatePages ( - AllocateMaxAddress, - EfiACPIMemoryNVS, - EFI_SIZE_TO_PAGES (LegacyRegionSize), - &LegacyRegionBase - ); - ASSERT_EFI_ERROR (Status); - - ZeroMem ((VOID *)(UINTN)LegacyRegionBase, LegacyRegionSize); - - mThunkContext.RealModeBuffer = (VOID *)(UINTN)LegacyRegionBase; - mThunkContext.RealModeBufferSize = LegacyRegionSize; - mThunkContext.ThunkAttributes = 3; - AsmPrepareThunk16 (&mThunkContext); -} - -BOOLEAN -EFIAPI -LegacyBiosInt86 ( - IN UINT8 BiosInt, - IN EFI_IA32_REGISTER_SET *Regs - ) -{ - UINTN Status; - BOOLEAN InterruptsEnabled; - IA32_REGISTER_SET ThunkRegSet; - BOOLEAN Ret; - UINT16 *Stack16; - - if (!gLegacy8259 || !mThunkContext.RealModeBuffer) { - return FALSE; - } - - Regs->X.Flags.Reserved1 = 1; - Regs->X.Flags.Reserved2 = 0; - Regs->X.Flags.Reserved3 = 0; - Regs->X.Flags.Reserved4 = 0; - Regs->X.Flags.IOPL = 3; - Regs->X.Flags.NT = 0; - Regs->X.Flags.IF = 1; - Regs->X.Flags.TF = 0; - Regs->X.Flags.CF = 0; - - ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet)); - ThunkRegSet.E.EDI = Regs->E.EDI; - ThunkRegSet.E.ESI = Regs->E.ESI; - ThunkRegSet.E.EBP = Regs->E.EBP; - ThunkRegSet.E.EBX = Regs->E.EBX; - ThunkRegSet.E.EDX = Regs->E.EDX; - ThunkRegSet.E.ECX = Regs->E.ECX; - ThunkRegSet.E.EAX = Regs->E.EAX; - ThunkRegSet.E.DS = Regs->E.DS; - ThunkRegSet.E.ES = Regs->E.ES; - - CopyMem (&(ThunkRegSet.E.EFLAGS), &(Regs->E.EFlags), sizeof (UINT32)); - - // - // The call to Legacy16 is a critical section to EFI - // - InterruptsEnabled = SaveAndDisableInterrupts (); - - // - // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases. - // - Status = gLegacy8259->SetMode (gLegacy8259, Efi8259LegacyMode, NULL, NULL); - ASSERT_EFI_ERROR (Status); - - Stack16 = (UINT16 *)((UINT8 *)mThunkContext.RealModeBuffer + mThunkContext.RealModeBufferSize - sizeof (UINT16)); - Stack16 -= sizeof (ThunkRegSet.E.EFLAGS) / sizeof (UINT16); - CopyMem (Stack16, &ThunkRegSet.E.EFLAGS, sizeof (ThunkRegSet.E.EFLAGS)); - - ThunkRegSet.E.SS = (UINT16)(((UINTN)Stack16 >> 16) << 12); - ThunkRegSet.E.ESP = (UINT16)(UINTN)Stack16; - ThunkRegSet.E.Eip = (UINT16)((volatile UINT32 *)NULL)[BiosInt]; - ThunkRegSet.E.CS = (UINT16)(((volatile UINT32 *)NULL)[BiosInt] >> 16); - - mThunkContext.RealModeState = &ThunkRegSet; - AsmThunk16 (&mThunkContext); - - // - // Restore protected mode interrupt state - // - Status = gLegacy8259->SetMode (gLegacy8259, Efi8259ProtectedMode, NULL, NULL); - ASSERT_EFI_ERROR (Status); - - // - // End critical section - // - SetInterruptState (InterruptsEnabled); - - Regs->E.EDI = ThunkRegSet.E.EDI; - Regs->E.ESI = ThunkRegSet.E.ESI; - Regs->E.EBP = ThunkRegSet.E.EBP; - Regs->E.EBX = ThunkRegSet.E.EBX; - Regs->E.EDX = ThunkRegSet.E.EDX; - Regs->E.ECX = ThunkRegSet.E.ECX; - Regs->E.EAX = ThunkRegSet.E.EAX; - Regs->E.SS = ThunkRegSet.E.SS; - Regs->E.CS = ThunkRegSet.E.CS; - Regs->E.DS = ThunkRegSet.E.DS; - Regs->E.ES = ThunkRegSet.E.ES; - - CopyMem (&(Regs->E.EFlags), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32)); - - Ret = (BOOLEAN)(Regs->E.EFlags.CF == 1); - - return Ret; -} diff --git a/Legacy/BootPlatform/CpuDxe/CpuDxe.h b/Legacy/BootPlatform/CpuDxe/CpuDxe.h index a28bd5cf..10010d3f 100644 --- a/Legacy/BootPlatform/CpuDxe/CpuDxe.h +++ b/Legacy/BootPlatform/CpuDxe/CpuDxe.h @@ -26,6 +26,7 @@ Abstract: #include #include #include +#include #include #include @@ -130,11 +131,4 @@ InitDescriptor ( VOID ); -BOOLEAN -EFIAPI -LegacyBiosInt86 ( - IN UINT8 BiosInt, - IN EFI_IA32_REGISTER_SET *Regs - ); - #endif diff --git a/Legacy/BootPlatform/CpuDxe/CpuDxe.inf b/Legacy/BootPlatform/CpuDxe/CpuDxe.inf index d105af51..214e6655 100644 --- a/Legacy/BootPlatform/CpuDxe/CpuDxe.inf +++ b/Legacy/BootPlatform/CpuDxe/CpuDxe.inf @@ -26,6 +26,7 @@ ENTRY_POINT = InitializeCpu [Packages] + OpenCorePkg/OpenCorePkg.dec OpenCorePkg/OpenDuetPkg.dec MdePkg/MdePkg.dec OvmfPkg/OvmfPkg.dec @@ -35,6 +36,7 @@ PrintLib UefiBootServicesTableLib BaseMemoryLib + OcLegacyThunkLib [Sources.Ia32] Ia32/CpuInterrupt.nasm diff --git a/Library/DuetBdsLib/BdsPlatform.c b/Library/DuetBdsLib/BdsPlatform.c index 8a14fcff..8d6f5a61 100644 --- a/Library/DuetBdsLib/BdsPlatform.c +++ b/Library/DuetBdsLib/BdsPlatform.c @@ -519,123 +519,6 @@ UpdateMemoryMap ( } } -STATIC -EFI_STATUS -DisableUsbLegacySupport ( - VOID - ) - -/*++ - -Routine Description: - Disable the USB legacy Support in all Ehci and Uhci. - This function assume all PciIo handles have been created in system. - -Arguments: - None - -Returns: - EFI_SUCCESS - EFI_NOT_FOUND ---*/ -{ - EFI_STATUS Status; - EFI_HANDLE *HandleArray; - UINTN HandleArrayCount; - UINTN Index; - EFI_PCI_IO_PROTOCOL *PciIo; - UINT8 Class[3]; - UINT16 Command; - UINT32 HcCapParams; - UINT32 ExtendCap; - UINT32 Value; - UINT32 TimeOut; - - // - // Find the usb host controller - // - Status = gBS->LocateHandleBuffer ( - ByProtocol, - &gEfiPciIoProtocolGuid, - NULL, - &HandleArrayCount, - &HandleArray - ); - if (!EFI_ERROR (Status)) { - for (Index = 0; Index < HandleArrayCount; Index++) { - Status = gBS->HandleProtocol ( - HandleArray[Index], - &gEfiPciIoProtocolGuid, - (VOID **)&PciIo - ); - if (!EFI_ERROR (Status)) { - // - // Find the USB host controller controller - // - Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class); - if (!EFI_ERROR (Status)) { - if ((PCI_CLASS_SERIAL == Class[2]) && - (PCI_CLASS_SERIAL_USB == Class[1])) - { - if (PCI_IF_UHCI == Class[0]) { - // - // Found the UHCI, then disable the legacy support - // - Command = 0; - Status = PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0xC0, 1, &Command); - } else if (PCI_IF_EHCI == Class[0]) { - // - // Found the EHCI, then disable the legacy support - // - Status = PciIo->Mem.Read ( - PciIo, - EfiPciIoWidthUint32, - 0, ///< EHC_BAR_INDEX - (UINT64)0x08, ///< EHC_HCCPARAMS_OFFSET - 1, - &HcCapParams - ); - - ExtendCap = (HcCapParams >> 8) & 0xFF; - // - // Disable the SMI in USBLEGCTLSTS firstly - // Not doing this may result in a hardlock soon after - // - PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value); - Value &= 0xFFFF0000; - PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ExtendCap + 0x4, 1, &Value); - - // - // Get EHCI Ownership from legacy bios - // - PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value); - Value |= (0x1 << 24); - PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value); - - TimeOut = 40; - while (TimeOut--) { - gBS->Stall (500); - - PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, ExtendCap, 1, &Value); - - if ((Value & 0x01010000) == 0x01000000) { - break; - } - } - } - } - } - } - } - - gBS->FreePool (HandleArray); - } else { - return Status; - } - - return EFI_SUCCESS; -} - STATIC EFI_STATUS ConnectRootBridge ( @@ -1091,14 +974,6 @@ Returns: DetectAndPreparePlatformPciDevicePath (TRUE); } - // - // The ConIn devices connection will start the USB bus, should disable all - // Usb legacy support firstly. - // Caution: Must ensure the PCI bus driver has been started. Since the - // ConnectRootBridge() will create all the PciIo protocol, it's safe here now - // - DisableUsbLegacySupport (); - // // Connect the all the default console with current console variable // diff --git a/Library/OcBootManagementLib/BootEntryManagement.c b/Library/OcBootManagementLib/BootEntryManagement.c index 5ccdb05d..f0a903ce 100644 --- a/Library/OcBootManagementLib/BootEntryManagement.c +++ b/Library/OcBootManagementLib/BootEntryManagement.c @@ -691,7 +691,7 @@ InternalAddBootEntryFromCustomEntry ( return EFI_OUT_OF_RESOURCES; } - if (!CustomEntry->SystemAction) { + if (!CustomEntry->ExternalSystemAction && !CustomEntry->SystemAction) { ASSERT (CustomEntry->Path != NULL); PathName = AsciiStrCopyToUnicode (CustomEntry->Path, 0); if (PathName == NULL) { @@ -714,12 +714,25 @@ InternalAddBootEntryFromCustomEntry ( DEBUG_INFO, "OCB: Adding custom entry %s (%a|B:%d) -> %a\n", BootEntry->Name, - CustomEntry->SystemAction != NULL ? "action" : (CustomEntry->Tool ? "tool" : "os"), + CustomEntry->ExternalSystemAction != NULL ? "ext-action" : (CustomEntry->SystemAction != NULL ? "action" : (CustomEntry->Tool ? "tool" : "os")), IsBootEntryProtocol, CustomEntry->Path )); - if (CustomEntry->SystemAction) { + if (CustomEntry->ExternalSystemAction) { + BootEntry->Type = OC_BOOT_EXTERNAL_SYSTEM; + BootEntry->ExternalSystemAction = CustomEntry->ExternalSystemAction; + BootEntry->ExternalSystemGetDevicePath = CustomEntry->ExternalSystemGetDevicePath; + BootEntry->AudioBasePath = CustomEntry->AudioBasePath; + BootEntry->AudioBaseType = CustomEntry->AudioBaseType; + BootEntry->IsExternal = CustomEntry->External; + BootEntry->DevicePath = DuplicateDevicePath (CustomEntry->ExternalSystemDevicePath); + + if (BootEntry->DevicePath == NULL) { + FreeBootEntry (BootEntry); + return EFI_OUT_OF_RESOURCES; + } + } else if (CustomEntry->SystemAction) { BootEntry->Type = OC_BOOT_SYSTEM; BootEntry->SystemAction = CustomEntry->SystemAction; BootEntry->AudioBasePath = CustomEntry->AudioBasePath; @@ -829,7 +842,7 @@ InternalAddBootEntryFromCustomEntry ( BootEntry->ExposeDevicePath = CustomEntry->RealPath; BootEntry->FullNvramAccess = CustomEntry->FullNvramAccess; - if (BootEntry->SystemAction != NULL) { + if ((BootEntry->ExternalSystemAction != NULL) || (BootEntry->SystemAction != NULL)) { ASSERT (CustomEntry->Arguments == NULL); } else { ASSERT (CustomEntry->Arguments != NULL); @@ -847,7 +860,7 @@ InternalAddBootEntryFromCustomEntry ( BootEntry->IsCustom = TRUE; BootEntry->IsBootEntryProtocol = IsBootEntryProtocol; - if (IsBootEntryProtocol && (BootEntry->SystemAction == NULL)) { + if (IsBootEntryProtocol && (BootEntry->ExternalSystemAction == NULL) && (BootEntry->SystemAction == NULL)) { PartitionEntry = OcGetGptPartitionEntry (FileSystem->Handle); if (PartitionEntry == NULL) { CopyGuid (&BootEntry->UniquePartitionGUID, &gEfiPartTypeUnusedGuid); @@ -1212,8 +1225,10 @@ AddBootEntryFromBootOption ( EFI_HANDLE FileSystemHandle; OC_BOOT_FILESYSTEM *FileSystem; UINTN DevicePathSize; + CHAR16 *TextDevicePath; INTN NumPatchedNodes; BOOLEAN IsAppleLegacy; + BOOLEAN IsAppleLegacyHandled; BOOLEAN IsRoot; EFI_LOAD_OPTION *LoadOption; UINTN LoadOptionSize; @@ -1305,6 +1320,7 @@ AddBootEntryFromBootOption ( // // Expand BootCamp device path to EFI partition device path. // + IsAppleLegacyHandled = FALSE; if (IsAppleLegacy) { // // BootCampHD always refers to a full Device Path. Failure to patch @@ -1316,13 +1332,73 @@ AddBootEntryFromBootOption ( return EFI_NOT_FOUND; } + // + // Attempt to handle detected legacy OS via Apple legacy interface. + // RemainingDevicePath = DevicePath; - DevicePath = OcDiskFindSystemPartitionPath ( + DevicePath = OcDiskFindActiveMbrPartitionPath ( DevicePath, &DevicePathSize, &FileSystemHandle ); + // + // Disk with MBR or hybrid MBR was detected. + // + if (DevicePath != NULL) { + TextDevicePath = ConvertDevicePathToText (DevicePath, FALSE, FALSE); + if (TextDevicePath != NULL) { + // + // Add entry from externally provided legacy interface. + // Boot entry ID must be active partition Device Path. + // + Status = OcAddEntriesFromBootEntryProtocol ( + BootContext, + CustomFileSystem, + EntryProtocolHandles, + EntryProtocolHandleCount, + TextDevicePath, + TRUE, + FALSE + ); + if (!EFI_ERROR (Status)) { + if (EntryProtocolId != NULL) { + *EntryProtocolId = TextDevicePath; + } + + FileSystem = CustomFileSystem; + IsAppleLegacyHandled = TRUE; + } else { + FreePool (TextDevicePath); + } + } + } + + if (!IsAppleLegacyHandled) { + // + // Boot option was set to Apple legacy interface incorrectly by macOS. + // This will occur on Macs that normally boot Windows in legacy mode, + // but have Windows installed in UEFI mode. + // + // Locate the ESP from the BootCampHD Device Path instead. + // + DevicePath = OcDiskFindSystemPartitionPath ( + RemainingDevicePath, + &DevicePathSize, + &FileSystemHandle + ); + + // + // Ensure that we are allowed to boot from this filesystem. + // + if (DevicePath != NULL) { + FileSystem = InternalFileSystemForHandle (BootContext, FileSystemHandle, LazyScan, NULL); + if (FileSystem == NULL) { + DevicePath = NULL; + } + } + } + FreePool (RemainingDevicePath); // @@ -1330,16 +1406,6 @@ AddBootEntryFromBootOption ( // IsRoot = TRUE; - // - // Ensure that we are allowed to boot from this filesystem. - // - if (DevicePath != NULL) { - FileSystem = InternalFileSystemForHandle (BootContext, FileSystemHandle, LazyScan, NULL); - if (FileSystem == NULL) { - DevicePath = NULL; - } - } - // // The Device Path returned by OcDiskFindSystemPartitionPath() is a pointer // to an installed protocol. Duplicate it so we own the memory. @@ -1565,6 +1631,10 @@ AddBootEntryFromBootOption ( FreePool (DevicePath); } + if (IsAppleLegacyHandled) { + return EFI_SUCCESS; + } + // // We may have a Boot#### entry pointing to macOS with full DP (up to boot.efi), // so IsRoot will be true. However, if this is APFS, we may still have: @@ -2125,11 +2195,6 @@ OcScanForBootEntries ( AddBootEntryFromSelfRecovery (BootContext, FileSystem); } - if (DefaultEntryId != NULL) { - FreePool (DefaultEntryId); - DefaultEntryId = NULL; - } - if (CustomFileSystem != NULL) { // // Insert the custom file system last for entry order. @@ -2150,12 +2215,17 @@ OcScanForBootEntries ( CustomFileSystem, EntryProtocolHandles, EntryProtocolHandleCount, - NULL, + DefaultEntryId, FALSE, FALSE ); } + if (DefaultEntryId != NULL) { + FreePool (DefaultEntryId); + DefaultEntryId = NULL; + } + OcFreeBootEntryProtocolHandles (&EntryProtocolHandles); if (BootContext->BootEntryCount == 0) { @@ -2440,6 +2510,11 @@ OcLoadBootEntry ( EFI_HANDLE EntryHandle; INTERNAL_DMG_LOAD_CONTEXT DmgLoadContext; + if ((BootEntry->Type & OC_BOOT_EXTERNAL_SYSTEM) != 0) { + ASSERT (BootEntry->ExternalSystemAction != NULL); + return BootEntry->ExternalSystemAction (Context, BootEntry->DevicePath); + } + if ((BootEntry->Type & OC_BOOT_SYSTEM) != 0) { ASSERT (BootEntry->SystemAction != NULL); return BootEntry->SystemAction (Context); diff --git a/Library/OcBootManagementLib/BootEntryProtocol.c b/Library/OcBootManagementLib/BootEntryProtocol.c index 724fd8cc..6bcde243 100644 --- a/Library/OcBootManagementLib/BootEntryProtocol.c +++ b/Library/OcBootManagementLib/BootEntryProtocol.c @@ -250,14 +250,6 @@ OcAddEntriesFromBootEntryProtocol ( ASSERT (!CreateDefault || (DefaultEntryId != NULL)); - // - // Non-filesystem entries cannot be saved as normal default boot option, - // but can be triggered as default boot item by boot entry protocol hotkey. - // - if (!CreateForHotKey && CreateDefault && (FileSystem->Handle == OC_CUSTOM_FS_HANDLE)) { - return EFI_NOT_FOUND; - } - AddEntriesContext.ReturnStatus = EFI_NOT_FOUND; AddEntriesContext.BootContext = BootContext; AddEntriesContext.FileSystem = FileSystem; diff --git a/Library/OcBootManagementLib/DefaultEntryChoice.c b/Library/OcBootManagementLib/DefaultEntryChoice.c index 5c118fc0..94b36c93 100644 --- a/Library/OcBootManagementLib/DefaultEntryChoice.c +++ b/Library/OcBootManagementLib/DefaultEntryChoice.c @@ -795,6 +795,7 @@ OcSetDefaultBootEntry ( UINTN BootChosenIndex; UINTN Index; UINTN DevicePathSize; + UINTN ExtSystemDevPathSize; UINTN LoadOptionSize; UINTN LoadOptionIdSize; UINTN LoadOptionNameSize; @@ -804,6 +805,7 @@ OcSetDefaultBootEntry ( CONST OC_CUSTOM_BOOT_DEVICE_PATH *CustomDevPath; CONST OC_ENTRY_PROTOCOL_DEVICE_PATH *EntryProtocolDevPath; + EFI_DEVICE_PATH_PROTOCOL *ExtSystemDevPath; VENDOR_DEVICE_PATH *DestCustomDevPath; FILEPATH_DEVICE_PATH *DestCustomEntryName; EFI_DEVICE_PATH_PROTOCOL *DestCustomEndNode; @@ -822,6 +824,20 @@ OcSetDefaultBootEntry ( return EFI_INVALID_PARAMETER; } + // + // Get final device path for external boot system entries. + // + ExtSystemDevPath = NULL; + if ((Entry->Type == OC_BOOT_EXTERNAL_SYSTEM) && (Entry->ExternalSystemGetDevicePath != NULL)) { + ExtSystemDevPath = Entry->DevicePath; + Status = Entry->ExternalSystemGetDevicePath (Context, &ExtSystemDevPath); + if (EFI_ERROR (Status)) { + ExtSystemDevPath = NULL; + } else { + ExtSystemDevPathSize = GetDevicePathSize (ExtSystemDevPath); + } + } + if (Context->CustomBootGuid) { BootVariableGuid = &gOcVendorVariableGuid; BootOrderName = OC_VENDOR_BOOT_ORDER_VARIABLE_NAME; @@ -874,35 +890,42 @@ OcSetDefaultBootEntry ( continue; } - BootOptionRemainingDevicePath = BootOptionDevicePath; - Status = gBS->LocateDevicePath ( - &gEfiSimpleFileSystemProtocolGuid, - &BootOptionRemainingDevicePath, - &DeviceHandle - ); - - if (!EFI_ERROR (Status)) { - MatchedEntry = InternalMatchBootEntryByDevicePath ( - Entry, - BootOptionDevicePath, - BootOptionRemainingDevicePath, - LoadOption->FilePathListLength, - FALSE - ); + if (ExtSystemDevPath != NULL) { + DevicePathSize = GetDevicePathSize (BootOptionDevicePath); + if (DevicePathSize >= ExtSystemDevPathSize) { + MatchedEntry = CompareMem (BootOptionDevicePath, ExtSystemDevPath, ExtSystemDevPathSize) == 0; + } } else { - CustomDevPath = InternalGetOcCustomDevPath (BootOptionDevicePath); - if (CustomDevPath != NULL) { - MatchedEntry = InternalMatchCustomBootEntryByDevicePath ( + BootOptionRemainingDevicePath = BootOptionDevicePath; + Status = gBS->LocateDevicePath ( + &gEfiSimpleFileSystemProtocolGuid, + &BootOptionRemainingDevicePath, + &DeviceHandle + ); + + if (!EFI_ERROR (Status)) { + MatchedEntry = InternalMatchBootEntryByDevicePath ( Entry, - CustomDevPath + BootOptionDevicePath, + BootOptionRemainingDevicePath, + LoadOption->FilePathListLength, + FALSE ); } else { - EntryProtocolDevPath = InternalGetOcEntryProtocolDevPath (BootOptionDevicePath); - if (EntryProtocolDevPath != NULL) { - MatchedEntry = InternalMatchEntryProtocolEntryByDevicePath ( + CustomDevPath = InternalGetOcCustomDevPath (BootOptionDevicePath); + if (CustomDevPath != NULL) { + MatchedEntry = InternalMatchCustomBootEntryByDevicePath ( Entry, - EntryProtocolDevPath + CustomDevPath ); + } else { + EntryProtocolDevPath = InternalGetOcEntryProtocolDevPath (BootOptionDevicePath); + if (EntryProtocolDevPath != NULL) { + MatchedEntry = InternalMatchEntryProtocolEntryByDevicePath ( + Entry, + EntryProtocolDevPath + ); + } } } } @@ -950,7 +973,9 @@ OcSetDefaultBootEntry ( } } - if (!Entry->IsCustom) { + if (ExtSystemDevPath != NULL) { + DevicePathSize = ExtSystemDevPathSize; + } else if (!Entry->IsCustom) { DevicePathSize = GetDevicePathSize (Entry->DevicePath); } else { DevicePathSize = SIZE_OF_OC_CUSTOM_BOOT_DEVICE_PATH @@ -996,7 +1021,9 @@ OcSetDefaultBootEntry ( CopyMem (LoadOption + 1, LoadOptionName, LoadOptionNameSize); } - if (!Entry->IsCustom) { + if (ExtSystemDevPath != NULL) { + CopyMem ((UINT8 *)(LoadOption + 1) + LoadOptionNameSize, ExtSystemDevPath, DevicePathSize); + } else if (!Entry->IsCustom) { CopyMem ((UINT8 *)(LoadOption + 1) + LoadOptionNameSize, Entry->DevicePath, DevicePathSize); } else { DestCustomDevPath = (VENDOR_DEVICE_PATH *)( @@ -1057,6 +1084,11 @@ OcSetDefaultBootEntry ( FreePool (LoadOption); + if (ExtSystemDevPath != NULL) { + FreePool (ExtSystemDevPath); + ExtSystemDevPath = NULL; + } + if (EFI_ERROR (Status)) { DEBUG (( DEBUG_INFO, @@ -1515,6 +1547,7 @@ InternalLoadBootEntry ( // // System entries are not loaded but called directly. // + ASSERT ((BootEntry->Type & OC_BOOT_EXTERNAL_SYSTEM) == 0); ASSERT ((BootEntry->Type & OC_BOOT_SYSTEM) == 0); ASSERT (Context != NULL); ASSERT (DmgLoadContext != NULL); diff --git a/Library/OcBootManagementLib/PolicyManagement.c b/Library/OcBootManagementLib/PolicyManagement.c index f1b52a05..a19faaab 100644 --- a/Library/OcBootManagementLib/PolicyManagement.c +++ b/Library/OcBootManagementLib/PolicyManagement.c @@ -75,6 +75,19 @@ OcGetDevicePolicyType ( SubType = DevicePathSubType (DevicePathWalker); switch (SubType) { case MSG_SATA_DP: + // + // Check if this SATA Bus has a CD connected. + // + DevicePathWalker = NextDevicePathNode (DevicePathWalker); + if ( !IsDevicePathEnd (DevicePathWalker) + && (DevicePathType (DevicePathWalker) == MEDIA_DEVICE_PATH) + && (DevicePathSubType (DevicePathWalker) == MEDIA_CDROM_DP)) + { + if (External != NULL) { + *External = TRUE; + } + } + return OC_SCAN_ALLOW_DEVICE_SATA; case MSG_SASEX_DP: return OC_SCAN_ALLOW_DEVICE_SASEX; @@ -335,6 +348,16 @@ OcGetBootDevicePathType ( *IsFolder = FALSE; } + // + // Detect firmware images such as the Apple legacy loader interface. + // + // Certain Mac models lock up if any additional probing of the device path + // is performed when the Apple legacy loader interface is being started. + // + if ((DevicePath->Type == MEDIA_DEVICE_PATH) && (DevicePath->SubType == MEDIA_PIWG_FW_FILE_DP)) { + return OC_BOOT_UNKNOWN; + } + Path = OcCopyDevicePathFullName (DevicePath, NULL); if (Path == NULL) { return OC_BOOT_UNKNOWN; diff --git a/Library/OcFileLib/GptPartitionEntry.c b/Library/OcFileLib/DiskMisc.c similarity index 53% rename from Library/OcFileLib/GptPartitionEntry.c rename to Library/OcFileLib/DiskMisc.c index b0f4b8a0..ca4407a5 100644 --- a/Library/OcFileLib/GptPartitionEntry.c +++ b/Library/OcFileLib/DiskMisc.c @@ -14,6 +14,8 @@ #include +#include + #include #include #include @@ -38,6 +40,8 @@ STATIC EFI_GUID mInternalPartitionEntryProtocolGuid = { 0x9FC6B19, 0xB8A1, 0x4A01, { 0x8D, 0xB1, 0x87, 0x94, 0xE7, 0x63, 0x4C, 0xA5 } }; +#define MBR_PARTITION_ACTIVE 0x80 + EFI_STATUS OcDiskInitializeContext ( OUT OC_DISK_CONTEXT *Context, @@ -47,6 +51,9 @@ OcDiskInitializeContext ( { EFI_STATUS Status; + ASSERT (Context != NULL); + ASSERT (DiskHandle != NULL); + // // Retrieve the Block I/O protocol. // @@ -140,6 +147,41 @@ OcDiskRead ( return Status; } +EFI_STATUS +OcDiskWrite ( + IN OC_DISK_CONTEXT *Context, + IN UINT64 Lba, + IN UINTN BufferSize, + IN VOID *Buffer + ) +{ + EFI_STATUS Status; + + ASSERT (Context->BlockIo != NULL || Context->BlockIo2 != NULL); + ASSERT ((BufferSize & (Context->BlockSize - 1)) == 0); + + if (Context->BlockIo2 != NULL) { + Status = Context->BlockIo2->WriteBlocksEx ( + Context->BlockIo2, + Context->MediaId, + Lba, + NULL, + BufferSize, + Buffer + ); + } else { + Status = Context->BlockIo->WriteBlocks ( + Context->BlockIo, + Context->MediaId, + Lba, + BufferSize, + Buffer + ); + } + + return Status; +} + STATIC VOID InternalDebugPrintPartitionEntry ( @@ -171,9 +213,9 @@ InternalDebugPrintPartitionEntry ( STATIC EFI_HANDLE -InternalPartitionGetDiskHandle ( +InternalGetDiskHandle ( IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath, - IN UINTN HdNodeOffset, + IN BOOLEAN IsPartitionPath, OUT BOOLEAN *HasBlockIo2 ) { @@ -181,27 +223,19 @@ InternalPartitionGetDiskHandle ( EFI_STATUS Status; - EFI_DEVICE_PATH_PROTOCOL *PrefixPath; + EFI_DEVICE_PATH_PROTOCOL *DiskPath; EFI_DEVICE_PATH_PROTOCOL *TempPath; ASSERT (HdDevicePath != NULL); - ASSERT (HdNodeOffset < GetDevicePathSize (HdDevicePath)); ASSERT (HasBlockIo2 != NULL); - PrefixPath = DuplicateDevicePath (HdDevicePath); - if (PrefixPath == NULL) { - DEBUG ((DEBUG_INFO, "OCPI: DP allocation error\n")); - return NULL; + if (IsPartitionPath) { + DiskPath = OcDiskGetDevicePath (HdDevicePath); + } else { + DiskPath = HdDevicePath; } - // - // Strip the HD node in order to retrieve the last node supporting Block I/O - // before it, which is going to be its disk. - // - TempPath = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)PrefixPath + HdNodeOffset); - SetDevicePathEndNode (TempPath); - - TempPath = PrefixPath; + TempPath = DiskPath; Status = gBS->LocateDevicePath ( &gEfiBlockIo2ProtocolGuid, &TempPath, @@ -210,7 +244,7 @@ InternalPartitionGetDiskHandle ( *HasBlockIo2 = !EFI_ERROR (Status); if (EFI_ERROR (Status)) { - TempPath = PrefixPath; + TempPath = DiskPath; Status = gBS->LocateDevicePath ( &gEfiBlockIoProtocolGuid, &TempPath, @@ -222,17 +256,71 @@ InternalPartitionGetDiskHandle ( DebugPrintDevicePath ( DEBUG_INFO, "OCPI: Failed to locate disk", - PrefixPath + TempPath ); DiskHandle = NULL; } - FreePool (PrefixPath); + if (IsPartitionPath && (DiskPath != NULL)) { + FreePool (DiskPath); + } return DiskHandle; } +/** + Retrieve the disk's Device Path from a partition's Device Path. + + @param[in] HdDevicePath The Device Path of the partition. + + @retval Device Path or NULL +**/ +EFI_DEVICE_PATH_PROTOCOL * +OcDiskGetDevicePath ( + IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *PrefixPath; + EFI_DEVICE_PATH_PROTOCOL *TempPath; + CONST EFI_DEVICE_PATH_PROTOCOL *HdNode; + + ASSERT (HdDevicePath != NULL); + + HdNode = FindDevicePathNodeWithType ( + HdDevicePath, + MEDIA_DEVICE_PATH, + MEDIA_HARDDRIVE_DP + ); + if (HdNode == NULL) { + HdNode = FindDevicePathNodeWithType ( + HdDevicePath, + MEDIA_DEVICE_PATH, + MEDIA_CDROM_DP + ); + if (HdNode == NULL) { + return NULL; + } + } + + PrefixPath = DuplicateDevicePath (HdDevicePath); + if (PrefixPath == NULL) { + DEBUG ((DEBUG_INFO, "OCPI: DP allocation error\n")); + return NULL; + } + + // + // Strip the HD node in order to retrieve the last node supporting Block I/O + // before it, which is going to be its disk. + // + TempPath = (EFI_DEVICE_PATH_PROTOCOL *)((UINTN)PrefixPath + ((UINTN)HdNode - (UINTN)HdDevicePath)); + SetDevicePathEndNode (TempPath); + + TempPath = PrefixPath; + + return TempPath; +} + /** Retrieve the disk's device handle from a partition's Device Path. @@ -244,29 +332,128 @@ OcPartitionGetDiskHandle ( IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath ) { - CONST HARDDRIVE_DEVICE_PATH *HdNode; - BOOLEAN Dummy; + BOOLEAN Dummy; ASSERT (HdDevicePath != NULL); - HdNode = (HARDDRIVE_DEVICE_PATH *)( - FindDevicePathNodeWithType ( - HdDevicePath, - MEDIA_DEVICE_PATH, - MEDIA_HARDDRIVE_DP - ) - ); - if (HdNode == NULL) { - return NULL; - } - - return InternalPartitionGetDiskHandle ( + return InternalGetDiskHandle ( HdDevicePath, - (UINTN)HdNode - (UINTN)HdDevicePath, + TRUE, &Dummy ); } +/** + Retrieve the partition's device handle from a partition's Device Path. + + @param[in] HdDevicePath The Device Path of the partition. + +**/ +EFI_HANDLE +OcPartitionGetPartitionHandle ( + IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath + ) +{ + BOOLEAN Dummy; + + ASSERT (HdDevicePath != NULL); + + return InternalGetDiskHandle ( + HdDevicePath, + FALSE, + &Dummy + ); +} + +BOOLEAN +OcIsDiskCdRom ( + IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath + ) +{ + EFI_DEVICE_PATH_PROTOCOL *DevicePathWalker; + + ASSERT (DiskDevicePath != NULL); + + DevicePathWalker = DiskDevicePath; + while (!IsDevicePathEnd (DevicePathWalker)) { + if ( (DevicePathType (DevicePathWalker) == MEDIA_DEVICE_PATH) + && (DevicePathSubType (DevicePathWalker) == MEDIA_CDROM_DP)) + { + return TRUE; + } + + DevicePathWalker = NextDevicePathNode (DevicePathWalker); + } + + return FALSE; +} + +EFI_STATUS +OcDiskReadElTorito ( + IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath, + OUT UINT8 **Buffer, + OUT UINTN *BufferSize + ) +{ + EFI_STATUS Status; + UINT8 *BootBuffer; + UINTN BootBufferSize; + + CDROM_DEVICE_PATH *CdNode; + EFI_HANDLE DiskHandle; + OC_DISK_CONTEXT DiskContext; + + ASSERT (DiskDevicePath != NULL); + ASSERT (Buffer != NULL); + ASSERT (BufferSize != NULL); + + // + // Retrieve the CD-ROM Device Path information. + // + CdNode = (CDROM_DEVICE_PATH *)( + FindDevicePathNodeWithType ( + DiskDevicePath, + MEDIA_DEVICE_PATH, + MEDIA_CDROM_DP + ) + ); + if (CdNode == NULL) { + DEBUG ((DEBUG_INFO, "OCPI: Device Path does not describe a CD-ROM\n")); + return EFI_UNSUPPORTED; + } + + DiskHandle = OcPartitionGetDiskHandle (DiskDevicePath); + + Status = OcDiskInitializeContext (&DiskContext, DiskHandle, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // TODO: Unclear whether the sector size here is the native CD size 2048 or 512. + // + BootBufferSize = (UINTN)(CdNode->PartitionSize * DiskContext.BlockSize); + BootBuffer = AllocatePool (BootBufferSize); + if (BootBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = OcDiskRead ( + &DiskContext, + CdNode->PartitionStart, + BootBufferSize, + BootBuffer + ); + if (EFI_ERROR (Status)) { + FreePool (BootBuffer); + return Status; + } + + *Buffer = BootBuffer; + *BufferSize = BootBufferSize; + return EFI_SUCCESS; +} + EFI_DEVICE_PATH_PROTOCOL * OcDiskFindSystemPartitionPath ( IN CONST EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath, @@ -589,9 +776,9 @@ OcGetGptPartitionEntry ( return NULL; } - DiskHandle = InternalPartitionGetDiskHandle ( + DiskHandle = InternalGetDiskHandle ( FsDevicePath, - (UINTN)HdNode - (UINTN)FsDevicePath, + TRUE, &HasBlockIo2 ); if (DiskHandle == NULL) { @@ -636,3 +823,387 @@ OcGetGptPartitionEntry ( return PartEntry; } + +MASTER_BOOT_RECORD * +OcGetDiskMbrTable ( + IN EFI_HANDLE DiskHandle, + IN BOOLEAN CheckPartitions + ) +{ + EFI_STATUS Status; + MASTER_BOOT_RECORD *Mbr; + UINTN MbrSize; + OC_DISK_CONTEXT DiskContext; + UINTN Index; + BOOLEAN IsProtectiveMbr; + + ASSERT (DiskHandle != NULL); + + // + // Read first sector containing MBR table. + // + Status = OcDiskInitializeContext ( + &DiskContext, + DiskHandle, + TRUE + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + MbrSize = ALIGN_VALUE (sizeof (*Mbr), DiskContext.BlockSize); + Mbr = (MASTER_BOOT_RECORD *)AllocatePool (MbrSize); + if (Mbr == NULL) { + return NULL; + } + + Status = OcDiskRead ( + &DiskContext, + 0, + MbrSize, + Mbr + ); + if (EFI_ERROR (Status)) { + FreePool (Mbr); + return NULL; + } + + // + // Validate MBR signatures. + // + // If MBR is a protective one (as part of a GPT disk), ignore. + // Protective MBR is defined as a single partition of type 0xEE, other three partitions are to be zero. + // + if (Mbr->Signature != MBR_SIGNATURE) { + FreePool (Mbr); + return NULL; + } + + if (CheckPartitions) { + if ( (Mbr->Partition[0].OSIndicator == PMBR_GPT_PARTITION) + && (ReadUnaligned32 ((UINT32 *)Mbr->Partition[0].StartingLBA) == 0x01) + && (ReadUnaligned32 ((UINT32 *)Mbr->Partition[0].SizeInLBA) != 0)) + { + IsProtectiveMbr = TRUE; + for (Index = 1; Index < MAX_MBR_PARTITIONS; Index++) { + if ( (ReadUnaligned32 ((UINT32 *)Mbr->Partition[Index].StartingLBA) != 0) + || (ReadUnaligned32 ((UINT32 *)Mbr->Partition[Index].SizeInLBA) != 0)) + { + IsProtectiveMbr = FALSE; + break; + } + } + + if (IsProtectiveMbr) { + FreePool (Mbr); + return NULL; + } + } + } + + return Mbr; +} + +EFI_STATUS +OcDiskGetMbrPartitionIndex ( + IN EFI_HANDLE PartitionHandle, + OUT UINT8 *PartitionIndex + ) +{ + EFI_STATUS Status; + MASTER_BOOT_RECORD *Mbr; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_HANDLE DiskHandle; + CONST HARDDRIVE_DEVICE_PATH *HdNode; + UINT8 Index; + + ASSERT (PartitionHandle != NULL); + ASSERT (PartitionIndex != NULL); + + // + // Retrieve the partition Device Path information. + // + DevicePath = DevicePathFromHandle (PartitionHandle); + if (DevicePath == NULL) { + DEBUG ((DEBUG_INFO, "OCPI: Failed to retrieve Device Path\n")); + return EFI_UNSUPPORTED; + } + + HdNode = (HARDDRIVE_DEVICE_PATH *)( + FindDevicePathNodeWithType ( + DevicePath, + MEDIA_DEVICE_PATH, + MEDIA_HARDDRIVE_DP + ) + ); + if (HdNode == NULL) { + DEBUG ((DEBUG_INFO, "OCPI: Device Path does not describe a partition\n")); + return EFI_UNSUPPORTED; + } + + DiskHandle = OcPartitionGetDiskHandle (DevicePath); + if (DiskHandle == NULL) { + return EFI_UNSUPPORTED; + } + + // + // Get MBR from partition's disk. + // + Mbr = OcGetDiskMbrTable ( + DiskHandle, + TRUE + ); + if (Mbr == NULL) { + DEBUG ((DEBUG_INFO, "OCPI: Disk does not have an MBR partition table\n")); + return EFI_UNSUPPORTED; + } + + Status = EFI_NOT_FOUND; + for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) { + if ( (ReadUnaligned32 ((UINT32 *)Mbr->Partition[Index].StartingLBA) == HdNode->PartitionStart) + && (ReadUnaligned32 ((UINT32 *)Mbr->Partition[Index].SizeInLBA) == HdNode->PartitionSize)) + { + *PartitionIndex = Index; + Status = EFI_SUCCESS; + break; + } + } + + FreePool (Mbr); + + return Status; +} + +EFI_STATUS +OcDiskMarkMbrPartitionActive ( + IN EFI_HANDLE DiskHandle, + IN UINT8 PartitionIndex + ) +{ + EFI_STATUS Status; + MASTER_BOOT_RECORD *Mbr; + UINTN MbrSize; + UINTN Index; + OC_DISK_CONTEXT DiskContext; + + ASSERT (DiskHandle != NULL); + ASSERT (PartitionIndex < MAX_MBR_PARTITIONS); + + // + // Read first sector containing MBR table. + // + Status = OcDiskInitializeContext ( + &DiskContext, + DiskHandle, + TRUE + ); + if (EFI_ERROR (Status)) { + return Status; + } + + MbrSize = ALIGN_VALUE (sizeof (*Mbr), DiskContext.BlockSize); + Mbr = (MASTER_BOOT_RECORD *)AllocatePool (MbrSize); + if (Mbr == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = OcDiskRead ( + &DiskContext, + 0, + MbrSize, + Mbr + ); + if (EFI_ERROR (Status)) { + FreePool (Mbr); + return Status; + } + + // + // Validate MBR signatures. + // + // If MBR is a protective one (as part of a GPT disk), ignore. + // Protective MBR is defined as a single partition of type 0xEE, other three partitions are to be zero. + // + if (Mbr->Signature != MBR_SIGNATURE) { + FreePool (Mbr); + return EFI_UNSUPPORTED; + } + + // + // Mark desired partition as active. + // + for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) { + Mbr->Partition[Index].BootIndicator = 0x00; + } + + Mbr->Partition[PartitionIndex].BootIndicator = MBR_PARTITION_ACTIVE; + + // + // Write MBR to disk. + // + Status = OcDiskWrite ( + &DiskContext, + 0, + MbrSize, + Mbr + ); + + FreePool (Mbr); + + return Status; +} + +EFI_DEVICE_PATH_PROTOCOL * +OcDiskFindActiveMbrPartitionPath ( + IN EFI_DEVICE_PATH_PROTOCOL *DiskDevicePath, + OUT UINTN *PartitionDevicePathSize, + OUT EFI_HANDLE *PartitionDeviceHandle + ) +{ + EFI_STATUS Status; + EFI_HANDLE DiskHandle; + BOOLEAN HasBlockIo2; + UINTN Index; + INT32 ActivePartition; + BOOLEAN Result; + INTN CmpResult; + + UINTN NoHandles; + EFI_HANDLE *Handles; + EFI_DEVICE_PATH_PROTOCOL *PartitionDevicePath; + HARDDRIVE_DEVICE_PATH *HdNode; + MASTER_BOOT_RECORD *Mbr; + + UINTN DiskDpSize; + UINTN DiskDpCmpSize; + EFI_DEVICE_PATH_PROTOCOL *HdDevicePath; + UINTN HdDpSize; + + ASSERT (DiskDevicePath != NULL); + ASSERT (PartitionDevicePathSize != NULL); + ASSERT (PartitionDeviceHandle != NULL); + + DebugPrintDevicePath ( + DEBUG_INFO, + "OCPI: Locating MBR disk's active partition", + (EFI_DEVICE_PATH_PROTOCOL *)DiskDevicePath + ); + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &NoHandles, + &Handles + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OCPI: Failed to locate Block I/O handles\n")); + return NULL; + } + + // + // Get MBR partition table from disk. + // + DiskHandle = InternalGetDiskHandle ( + DiskDevicePath, + FALSE, + &HasBlockIo2 + ); + if (DiskHandle == NULL) { + return NULL; + } + + Mbr = OcGetDiskMbrTable ( + DiskHandle, + TRUE + ); + if (Mbr == NULL) { + return NULL; + } + + // + // Determine active partition based on first one with active partition set. + // Multiple active partitions should not occur but possible. + // + ActivePartition = -1; + for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) { + if (Mbr->Partition[Index].BootIndicator == MBR_PARTITION_ACTIVE) { + ActivePartition = (INT32)Index; + break; + } + } + + // + // No active partitions present. + // + if (ActivePartition == -1) { + DEBUG ((DEBUG_INFO, "OCPI: No active partitions found in MBR\n")); + FreePool (Mbr); + return NULL; + } + + // + // The partition's Device Path must be at least as big as the disk's (prefix) + // plus an additional HardDrive node. + // + DiskDpSize = GetDevicePathSize (DiskDevicePath); + Result = BaseOverflowAddUN ( + DiskDpSize, + sizeof (HARDDRIVE_DEVICE_PATH), + &DiskDpCmpSize + ); + if (Result) { + DEBUG ((DEBUG_INFO, "OCPI: HD node would overflow DP\n")); + FreePool (Mbr); + return NULL; + } + + PartitionDevicePath = NULL; + + for (Index = 0; Index < NoHandles; Index++) { + HdDevicePath = DevicePathFromHandle (Handles[Index]); + if (HdDevicePath == NULL) { + continue; + } + + HdDpSize = GetDevicePathSize (HdDevicePath); + if (HdDpSize < DiskDpCmpSize) { + continue; + } + + // + // Verify the partition's Device Path has the disk's prefixed. + // + CmpResult = CompareMem ( + HdDevicePath, + DiskDevicePath, + DiskDpSize - END_DEVICE_PATH_LENGTH + ); + if (CmpResult != 0) { + continue; + } + + if (CompareMem (HdDevicePath, DiskDevicePath, GetDevicePathSize (DiskDevicePath) - END_DEVICE_PATH_LENGTH) == 0) { + HdNode = (HARDDRIVE_DEVICE_PATH *)FindDevicePathNodeWithType ( + HdDevicePath, + MEDIA_DEVICE_PATH, + MEDIA_HARDDRIVE_DP + ); + if (HdNode != NULL) { + if (HdNode->PartitionStart == *((UINT32 *)Mbr->Partition[ActivePartition].StartingLBA)) { + DebugPrintDevicePath (DEBUG_INFO, "OCPI: Got active MBR partition device path", HdDevicePath); + + PartitionDevicePath = HdDevicePath; + *PartitionDevicePathSize = HdDpSize; + *PartitionDeviceHandle = Handles[Index]; + break; + } + } + } + } + + FreePool (Handles); + FreePool (Mbr); + + return PartitionDevicePath; +} diff --git a/Library/OcFileLib/OcFileLib.inf b/Library/OcFileLib/OcFileLib.inf index e81d5a24..d801c25b 100755 --- a/Library/OcFileLib/OcFileLib.inf +++ b/Library/OcFileLib/OcFileLib.inf @@ -33,7 +33,7 @@ LocateFileSystem.c OpenFile.c ReadFile.c - GptPartitionEntry.c + DiskMisc.c FirmwareFile.c FileMisc.c diff --git a/Library/OcLegacyThunkLib/OcLegacyThunkLib.c b/Library/OcLegacyThunkLib/OcLegacyThunkLib.c new file mode 100644 index 00000000..0cfa3c46 --- /dev/null +++ b/Library/OcLegacyThunkLib/OcLegacyThunkLib.c @@ -0,0 +1,477 @@ +/** @file + This file implements thunking to legacy 16-bit environment. + + Copyright (c) 2023, Goldfish64. All rights reserved.
+ Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.
+ SPDX-License-Identifier: BSD-2-Clause +**/ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +// +// 8254 Timer registers +// +#define TIMER0_COUNT_PORT 0x40 +#define TIMER1_COUNT_PORT 0x41 +#define TIMER2_COUNT_PORT 0x42 +#define TIMER_CONTROL_PORT 0x43 +#define TIMER0_CONTROL_WORD 0x36 + +// +// Vector base definitions +// +// +// 8259 Hardware definitions +// +#define LEGACY_MODE_BASE_VECTOR_MASTER 0x08 +#define LEGACY_MODE_BASE_VECTOR_SLAVE 0x70 + +// +// The original PC used INT8-F for master PIC. Since these mapped over +// processor exceptions TIANO moved the master PIC to INT68-6F. +// +// The vector base for slave PIC is set as 0x70 for PC-AT compatibility. +// +#define PROTECTED_MODE_BASE_VECTOR_MASTER 0x68 +#define PROTECTED_MODE_BASE_VECTOR_SLAVE 0x70 + +/** + Initialize legacy environment for BIOS INI caller. + + @param ThunkContext The instance pointer of THUNK_CONTEXT. +**/ +EFI_STATUS +OcLegacyThunkInitializeBiosIntCaller ( + THUNK_CONTEXT *ThunkContext + ) +{ + EFI_STATUS Status; + UINT32 RealModeBufferSize; + UINT32 ExtraStackSize; + EFI_PHYSICAL_ADDRESS LegacyRegionBase; + UINT32 LegacyRegionSize; + + // + // Get LegacyRegion + // + AsmGetThunk16Properties (&RealModeBufferSize, &ExtraStackSize); + LegacyRegionSize = (((RealModeBufferSize + ExtraStackSize) / EFI_PAGE_SIZE) + 1) * EFI_PAGE_SIZE; + LegacyRegionBase = LEGACY_REGION_BASE; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (LegacyRegionSize), + &LegacyRegionBase + ); + if (EFI_ERROR (Status)) { + return Status; + } + + ZeroMem ((VOID *)(UINTN)LegacyRegionBase, LegacyRegionSize); + + ThunkContext->RealModeBuffer = (VOID *)(UINTN)LegacyRegionBase; + ThunkContext->RealModeBufferSize = LegacyRegionSize; + ThunkContext->ThunkAttributes = THUNK_ATTRIBUTE_BIG_REAL_MODE|THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15; + AsmPrepareThunk16 (ThunkContext); + return Status; +} + +/** + Initialize interrupt redirection code and entries, because + IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f. + Or the interrupt will lost when we do thunk. + NOTE: We do not reset 8259 vector base, because it will cause pending + interrupt lost. + + @param Legacy8259 Instance pointer for EFI_LEGACY_8259_PROTOCOL. + +**/ +EFI_STATUS +OcLegacyThunkInitializeInterruptRedirection ( + IN EFI_LEGACY_8259_PROTOCOL *Legacy8259 + ) +{ + EFI_STATUS Status; + EFI_PHYSICAL_ADDRESS LegacyRegionBase; + UINTN LegacyRegionLength; + volatile UINT32 *IdtArray; + UINTN Index; + UINT8 ProtectedModeBaseVector; + + STATIC CONST UINT32 InterruptRedirectionCode[] = { + 0x90CF08CD, // INT8; IRET; NOP + 0x90CF09CD, // INT9; IRET; NOP + 0x90CF0ACD, // INTA; IRET; NOP + 0x90CF0BCD, // INTB; IRET; NOP + 0x90CF0CCD, // INTC; IRET; NOP + 0x90CF0DCD, // INTD; IRET; NOP + 0x90CF0ECD, // INTE; IRET; NOP + 0x90CF0FCD // INTF; IRET; NOP + }; + + // + // Get LegacyRegion + // + LegacyRegionLength = sizeof (InterruptRedirectionCode); + LegacyRegionBase = LEGACY_REGION_BASE; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiACPIMemoryNVS, + EFI_SIZE_TO_PAGES (LegacyRegionLength), + &LegacyRegionBase + ); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Copy code to legacy region + // + CopyMem ((VOID *)(UINTN)LegacyRegionBase, InterruptRedirectionCode, sizeof (InterruptRedirectionCode)); + + // + // Get VectorBase, it should be 0x68 + // + Status = Legacy8259->GetVector (Legacy8259, Efi8259Irq0, &ProtectedModeBaseVector); + ASSERT_EFI_ERROR (Status); + + // + // Patch IVT 0x68 ~ 0x6f + // + IdtArray = (UINT32 *)0; + for (Index = 0; Index < 8; Index++) { + IdtArray[ProtectedModeBaseVector + Index] = ((EFI_SEGMENT (LegacyRegionBase + Index * 4)) << 16) | (EFI_OFFSET (LegacyRegionBase + Index * 4)); + } + + return Status; +} + +/** + Disconnect all EFI graphics device handles in preparation for calling to legacy mode. +**/ +VOID +OcLegacyThunkDisconnectEfiGraphics ( + VOID + ) +{ + EFI_STATUS Status; + UINTN HandleCount; + EFI_HANDLE *HandleBuffer; + UINTN Index; + EFI_PCI_IO_PROTOCOL *PciIo; + PCI_CLASSCODE ClassCode; + + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiPciIoProtocolGuid, + NULL, + &HandleCount, + &HandleBuffer + ); + if (EFI_ERROR (Status)) { + return; + } + + for (Index = 0; Index < HandleCount; ++Index) { + Status = gBS->HandleProtocol ( + HandleBuffer[Index], + &gEfiPciIoProtocolGuid, + (VOID **)&PciIo + ); + + if (EFI_ERROR (Status)) { + continue; + } + + Status = PciIo->Pci.Read ( + PciIo, + EfiPciIoWidthUint8, + PCI_CLASSCODE_OFFSET, + sizeof (PCI_CLASSCODE) / sizeof (UINT8), + &ClassCode + ); + if (EFI_ERROR (Status)) { + continue; + } + + if ((ClassCode.BaseCode == PCI_CLASS_DISPLAY) && (ClassCode.SubClassCode == PCI_CLASS_DISPLAY_VGA)) { + Status = gBS->DisconnectController ( + HandleBuffer[Index], + NULL, + NULL + ); + DEBUG ((DEBUG_INFO, "OCLT: Disconnected graphics controller - %r\n", Status)); + } + } + + FreePool (HandleBuffer); +} + +/** + Thunk to 16-bit real mode and execute a software interrupt with a vector + of BiosInt. Regs will contain the 16-bit register context on entry and + exit. + + @param ThunkContext The instance pointer of THUNK_CONTEXT. + @param Legacy8259 Instance pointer for EFI_LEGACY_8259_PROTOCOL. + @param BiosInt Processor interrupt vector to invoke + @param Reg Register contexted passed into (and returned) from thunk to 16-bit mode + + @retval TRUE Thunk completed, and there were no BIOS errors in the target code. + See Regs for status. + @retval FALSE There was a BIOS error in the target code. +**/ +BOOLEAN +EFIAPI +OcLegacyThunkBiosInt86 ( + IN THUNK_CONTEXT *ThunkContext, + IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, + IN UINT8 BiosInt, + IN IA32_REGISTER_SET *Regs + ) +{ + UINTN Status; + IA32_REGISTER_SET ThunkRegSet; + BOOLEAN Ret; + UINT16 *Stack16; + BOOLEAN Enabled; + + ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet)); + ThunkRegSet.E.EFLAGS.Bits.Reserved_0 = 1; + ThunkRegSet.E.EFLAGS.Bits.Reserved_1 = 0; + ThunkRegSet.E.EFLAGS.Bits.Reserved_2 = 0; + ThunkRegSet.E.EFLAGS.Bits.Reserved_3 = 0; + ThunkRegSet.E.EFLAGS.Bits.IOPL = 3; + ThunkRegSet.E.EFLAGS.Bits.NT = 0; + ThunkRegSet.E.EFLAGS.Bits.IF = 1; + ThunkRegSet.E.EFLAGS.Bits.TF = 0; + ThunkRegSet.E.EFLAGS.Bits.CF = 0; + + ThunkRegSet.E.EDI = Regs->E.EDI; + ThunkRegSet.E.ESI = Regs->E.ESI; + ThunkRegSet.E.EBP = Regs->E.EBP; + ThunkRegSet.E.EBX = Regs->E.EBX; + ThunkRegSet.E.EDX = Regs->E.EDX; + ThunkRegSet.E.ECX = Regs->E.ECX; + ThunkRegSet.E.EAX = Regs->E.EAX; + ThunkRegSet.E.DS = Regs->E.DS; + ThunkRegSet.E.ES = Regs->E.ES; + + // + // The call to Legacy16 is a critical section to EFI + // + Enabled = SaveAndDisableInterrupts (); + + // + // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases. + // + Status = Legacy8259->SetMode (Legacy8259, Efi8259LegacyMode, NULL, NULL); + ASSERT_EFI_ERROR (Status); + + Stack16 = (UINT16 *)((UINT8 *)ThunkContext->RealModeBuffer + ThunkContext->RealModeBufferSize - sizeof (UINT16)); + + ThunkRegSet.E.SS = (UINT16)(((UINTN)Stack16 >> 16) << 12); + ThunkRegSet.E.ESP = (UINT16)(UINTN)Stack16; + + ThunkRegSet.E.Eip = (UINT16)((volatile UINT32 *)NULL)[BiosInt]; + ThunkRegSet.E.CS = (UINT16)(((volatile UINT32 *)NULL)[BiosInt] >> 16); + ThunkContext->RealModeState = &ThunkRegSet; + AsmThunk16 (ThunkContext); + + // + // Restore protected mode interrupt state + // + Status = Legacy8259->SetMode (Legacy8259, Efi8259ProtectedMode, NULL, NULL); + ASSERT_EFI_ERROR (Status); + + // + // End critical section + // + SetInterruptState (Enabled); + + Regs->E.EDI = ThunkRegSet.E.EDI; + Regs->E.ESI = ThunkRegSet.E.ESI; + Regs->E.EBP = ThunkRegSet.E.EBP; + Regs->E.EBX = ThunkRegSet.E.EBX; + Regs->E.EDX = ThunkRegSet.E.EDX; + Regs->E.ECX = ThunkRegSet.E.ECX; + Regs->E.EAX = ThunkRegSet.E.EAX; + Regs->E.SS = ThunkRegSet.E.SS; + Regs->E.CS = ThunkRegSet.E.CS; + Regs->E.DS = ThunkRegSet.E.DS; + Regs->E.ES = ThunkRegSet.E.ES; + + CopyMem (&(Regs->E.EFLAGS), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32)); + + Ret = (BOOLEAN)(Regs->E.EFLAGS.Bits.CF == 1); + + return Ret; +} + +BOOLEAN +EFIAPI +OcLegacyThunkFarCall86 ( + IN THUNK_CONTEXT *ThunkContext, + IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, + IN UINT16 Segment, + IN UINT16 Offset, + IN IA32_REGISTER_SET *Regs, + IN VOID *Stack, + IN UINTN StackSize + ) +{ + UINTN Status; + UINT16 *Stack16; + IA32_REGISTER_SET ThunkRegSet; + BOOLEAN Ret; + UINT64 TimerPeriod; + BOOLEAN Enabled; + + EFI_TIMER_ARCH_PROTOCOL *TimerProtocol; + + ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet)); + ThunkRegSet.E.EFLAGS.Bits.Reserved_0 = 1; + ThunkRegSet.E.EFLAGS.Bits.Reserved_1 = 0; + ThunkRegSet.E.EFLAGS.Bits.Reserved_2 = 0; + ThunkRegSet.E.EFLAGS.Bits.Reserved_3 = 0; + ThunkRegSet.E.EFLAGS.Bits.IOPL = 3; + ThunkRegSet.E.EFLAGS.Bits.NT = 0; + ThunkRegSet.E.EFLAGS.Bits.IF = 1; + ThunkRegSet.E.EFLAGS.Bits.TF = 0; + ThunkRegSet.E.EFLAGS.Bits.CF = 0; + + ThunkRegSet.E.EDI = Regs->E.EDI; + ThunkRegSet.E.ESI = Regs->E.ESI; + ThunkRegSet.E.EBP = Regs->E.EBP; + ThunkRegSet.E.EBX = Regs->E.EBX; + ThunkRegSet.E.EDX = Regs->E.EDX; + ThunkRegSet.E.ECX = Regs->E.ECX; + ThunkRegSet.E.EAX = Regs->E.EAX; + ThunkRegSet.E.DS = Regs->E.DS; + ThunkRegSet.E.ES = Regs->E.ES; + + // + // The call to Legacy16 is a critical section to EFI + // + Enabled = SaveAndDisableInterrupts (); + + // + // Save current rate of DXE timer and disable it + // while executing in real mode. + // + Status = gBS->LocateProtocol ( + &gEfiTimerArchProtocolGuid, + NULL, + (VOID **)&TimerProtocol + ); + if (!EFI_ERROR (Status)) { + TimerProtocol->GetTimerPeriod (TimerProtocol, &TimerPeriod); + TimerProtocol->SetTimerPeriod (TimerProtocol, 0); + } else { + TimerProtocol = NULL; + } + + // + // Reset timer to default legacy rate of 54.9254. + // + IoWrite8 (TIMER_CONTROL_PORT, TIMER0_CONTROL_WORD); + IoWrite8 (TIMER0_COUNT_PORT, 0x00); + IoWrite8 (TIMER0_COUNT_PORT, 0x00); + + // + // Put the 8259 into its legacy mode by reprogramming the vector bases + // + Status = Legacy8259->SetVectorBase (Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE); + ASSERT_EFI_ERROR (Status); + + // + // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases. + // + Status = Legacy8259->SetMode (Legacy8259, Efi8259LegacyMode, NULL, NULL); + ASSERT_EFI_ERROR (Status); + + // + // Clear the error flag; thunk code may set it. Stack16 should be the high address. + // Make Stack16 address the low 16 bit must be not zero. + // + Stack16 = (UINT16 *)((UINT8 *)ThunkContext->RealModeBuffer + ThunkContext->RealModeBufferSize - sizeof (UINT16)); + + if ((Stack != NULL) && (StackSize != 0)) { + // + // Copy Stack to low memory stack + // + Stack16 -= StackSize / sizeof (UINT16); + CopyMem (Stack16, Stack, StackSize); + } + + ThunkRegSet.E.SS = (UINT16)(((UINTN)Stack16 >> 16) << 12); + ThunkRegSet.E.ESP = (UINT16)(UINTN)Stack16; + ThunkRegSet.E.CS = Segment; + ThunkRegSet.E.Eip = Offset; + + ThunkContext->RealModeState = &ThunkRegSet; + AsmThunk16 (ThunkContext); + + // + // EFI is likely trashed if we get here, but attempt to restore state. + // + if ((Stack != NULL) && (StackSize != 0)) { + // + // Copy low memory stack to Stack + // + CopyMem (Stack, Stack16, StackSize); + } + + // + // Restore protected mode interrupt state + // + Status = Legacy8259->SetMode (Legacy8259, Efi8259ProtectedMode, NULL, NULL); + ASSERT_EFI_ERROR (Status); + + ThunkContext->RealModeState = NULL; + + // + // Enable and restore rate of DXE Timer + // + if (TimerProtocol != NULL) { + TimerProtocol->SetTimerPeriod (TimerProtocol, TimerPeriod); + } + + // + // End critical section + // + SetInterruptState (Enabled); + + Regs->E.EDI = ThunkRegSet.E.EDI; + Regs->E.ESI = ThunkRegSet.E.ESI; + Regs->E.EBP = ThunkRegSet.E.EBP; + Regs->E.EBX = ThunkRegSet.E.EBX; + Regs->E.EDX = ThunkRegSet.E.EDX; + Regs->E.ECX = ThunkRegSet.E.ECX; + Regs->E.EAX = ThunkRegSet.E.EAX; + Regs->E.SS = ThunkRegSet.E.SS; + Regs->E.CS = ThunkRegSet.E.CS; + Regs->E.DS = ThunkRegSet.E.DS; + Regs->E.ES = ThunkRegSet.E.ES; + + CopyMem (&(Regs->E.EFLAGS), &(ThunkRegSet.E.EFLAGS), sizeof (UINT32)); + + Ret = (BOOLEAN)(Regs->E.EFLAGS.Bits.CF == 1); + + return Ret; +} diff --git a/Library/OcLegacyThunkLib/OcLegacyThunkLib.inf b/Library/OcLegacyThunkLib/OcLegacyThunkLib.inf new file mode 100644 index 00000000..7f9e9bc8 --- /dev/null +++ b/Library/OcLegacyThunkLib/OcLegacyThunkLib.inf @@ -0,0 +1,53 @@ +## @file +# +# Component description file for the library handling thunking to legacy 16-bit environment. +# +# Copyright (C) 2023, Goldfish64. All rights reserved.
+# +# All rights reserved. +# +# This program and the accompanying materials +# are licensed and made available under the terms and conditions of the BSD License +# which accompanies this distribution. The full text of the license may be found at +# http://opensource.org/licenses/bsd-license.php +# +# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +# +## + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = OcLegacyThunkLib + FILE_GUID = 133D1AF1-8BB5-4F12-AC93-2DF858D9935F + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = OcLegacyThunkLib|PEIM DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_DRIVER UEFI_APPLICATION DXE_SMM_DRIVER + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 IPF EBC +# + +[Sources] + OcLegacyThunkLib.c + +[Packages] + MdePkg/MdePkg.dec + OpenCorePkg/OpenCorePkg.dec + OvmfPkg/OvmfPkg.dec + UefiCpuPkg/UefiCpuPkg.dec + +[Protocols] + gEfiLegacy8259ProtocolGuid + gEfiPciIoProtocolGuid + gEfiTimerArchProtocolGuid + +[LibraryClasses] + BaseMemoryLib + DebugLib + IoLib + MemoryAllocationLib + UefiBootServicesTableLib + UefiLib diff --git a/OpenCorePkg.dec b/OpenCorePkg.dec index e571ff9c..d3c4f30d 100755 --- a/OpenCorePkg.dec +++ b/OpenCorePkg.dec @@ -904,6 +904,9 @@ ## @libraryclass OcInputLib|Include/Acidanthera/Library/OcInputLib.h + ## @libraryclass + OcLegacyThunkLib|Include/Acidanthera/Library/OcLegacyThunkLib.h + ## @libraryclass OcLogAggregatorLib|Include/Acidanthera/Library/OcLogAggregatorLib.h diff --git a/OpenCorePkg.dsc b/OpenCorePkg.dsc index 212bab3b..4aba7840 100755 --- a/OpenCorePkg.dsc +++ b/OpenCorePkg.dsc @@ -114,6 +114,7 @@ OcHeciLib|OpenCorePkg/Library/OcHeciLib/OcHeciLib.inf OcHiiDatabaseLocalLib|OpenCorePkg/Library/OcHiiDatabaseLib/OcHiiDatabaseLocalLib.inf OcInputLib|OpenCorePkg/Library/OcInputLib/OcInputLib.inf + OcLegacyThunkLib|OpenCorePkg/Library/OcLegacyThunkLib/OcLegacyThunkLib.inf OcLogAggregatorLib|OpenCorePkg/Library/OcLogAggregatorLib/OcLogAggregatorLib.inf OcMachoLib|OpenCorePkg/Library/OcMachoLib/OcMachoLib.inf OcMacInfoLib|OpenCorePkg/Library/OcMacInfoLib/OcMacInfoLib.inf @@ -298,6 +299,7 @@ OpenCorePkg/Legacy/BootPlatform/BiosVideo/BiosVideo.inf OpenCorePkg/Platform/CrScreenshotDxe/CrScreenshotDxe.inf OpenCorePkg/Platform/OpenCanopy/OpenCanopy.inf + OpenCorePkg/Platform/OpenLegacyBoot/OpenLegacyBoot.inf OpenCorePkg/Platform/OpenLinuxBoot/OpenLinuxBoot.inf OpenCorePkg/Platform/OpenNtfsDxe/OpenNtfsDxe.inf OpenCorePkg/Platform/OpenPartitionDxe/PartitionDxe.inf diff --git a/OpenDuetPkg.dsc b/OpenDuetPkg.dsc index 97a30d07..2d749013 100644 --- a/OpenDuetPkg.dsc +++ b/OpenDuetPkg.dsc @@ -106,6 +106,7 @@ OcDevicePathLib|OpenCorePkg/Library/OcDevicePathLib/OcDevicePathLib.inf OcFileLib|OpenCorePkg/Library/OcFileLib/OcFileLib.inf OcGuardLib|OpenCorePkg/Library/OcGuardLib/OcGuardLib.inf + OcLegacyThunkLib|OpenCorePkg/Library/OcLegacyThunkLib/OcLegacyThunkLib.inf OcMemoryLib|OpenCorePkg/Library/OcMemoryLib/OcMemoryLib.inf OcMiscLib|OpenCorePkg/Library/OcMiscLib/OcMiscLib.inf OcStringLib|OpenCorePkg/Library/OcStringLib/OcStringLib.inf @@ -244,6 +245,7 @@ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutUgaSupport|FALSE gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathFromText|FALSE gEfiMdeModulePkgTokenSpaceGuid.PcdDevicePathSupportDevicePathToText|FALSE + gEfiMdeModulePkgTokenSpaceGuid.PcdTurnOffUsbLegacySupport|TRUE gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport|FALSE [PcdsFixedAtBuild] diff --git a/Platform/OpenCanopy/Views/BootPicker.c b/Platform/OpenCanopy/Views/BootPicker.c index 88b507da..48a8cefe 100644 --- a/Platform/OpenCanopy/Views/BootPicker.c +++ b/Platform/OpenCanopy/Views/BootPicker.c @@ -1453,6 +1453,14 @@ BootPickerEntriesSet ( Status = EFI_UNSUPPORTED; } + break; + case OC_BOOT_EXTERNAL_SYSTEM: + if (OcAsciiStriStr (Entry->Flavour, OC_FLAVOUR_WINDOWS) != NULL) { + Status = CopyLabel (&VolumeEntry->Label, &GuiContext->Labels[LABEL_WINDOWS]); + } else { + Status = CopyLabel (&VolumeEntry->Label, &GuiContext->Labels[LABEL_OTHER]); + } + break; case OC_BOOT_UNKNOWN: Status = CopyLabel (&VolumeEntry->Label, &GuiContext->Labels[LABEL_GENERIC_HDD]); diff --git a/Platform/OpenLegacyBoot/BiosDisk.c b/Platform/OpenLegacyBoot/BiosDisk.c new file mode 100644 index 00000000..c802de72 --- /dev/null +++ b/Platform/OpenLegacyBoot/BiosDisk.c @@ -0,0 +1,275 @@ +/** @file + Copyright (C) 2023, Goldfish64. All rights reserved.
+ SPDX-License-Identifier: BSD-3-Clause +**/ + +#include "LegacyBootInternal.h" + +// +// Int 13 BIOS Errors +// +#define BIOS_PASS 0x00 +#define BIOS_WRITE_PROTECTED 0x03 +#define BIOS_SECTOR_NOT_FOUND 0x04 +#define BIOS_RESET_FAILED 0x05 +#define BIOS_DISK_CHANGED 0x06 +#define BIOS_DRIVE_DOES_NOT_EXIST 0x07 +#define BIOS_DMA_ERROR 0x08 +#define BIOS_DATA_BOUNDRY_ERROR 0x09 +#define BIOS_BAD_SECTOR 0x0a +#define BIOS_BAD_TRACK 0x0b +#define BIOS_MEADIA_TYPE_NOT_FOUND 0x0c +#define BIOS_INVALED_FORMAT 0x0d +#define BIOS_ECC_ERROR 0x10 +#define BIOS_ECC_CORRECTED_ERROR 0x11 +#define BIOS_HARD_DRIVE_FAILURE 0x20 +#define BIOS_SEEK_FAILED 0x40 +#define BIOS_DRIVE_TIMEOUT 0x80 +#define BIOS_DRIVE_NOT_READY 0xaa +#define BIOS_UNDEFINED_ERROR 0xbb +#define BIOS_WRITE_FAULT 0xcc +#define BIOS_SENSE_FAILED 0xff + +typedef struct { + UINT8 PacketSizeInBytes; // 0x10 + UINT8 Zero; + UINT8 NumberOfBlocks; // Max 0x7f + UINT8 Zero2; + UINT32 SegOffset; + UINT64 Lba; +} DEVICE_ADDRESS_PACKET; + +#define BIOS_DISK_CHECK_BUFFER_SECTOR_COUNT 4 + +STATIC +EFI_STATUS +BiosDiskReset ( + IN THUNK_CONTEXT *ThunkContext, + IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, + IN UINT8 DriveNumber + ) +{ + IA32_REGISTER_SET Regs; + UINTN CarryFlag; + + ZeroMem (&Regs, sizeof (IA32_REGISTER_SET)); + + Regs.H.AH = 0x00; + Regs.H.DL = DriveNumber; + CarryFlag = OcLegacyThunkBiosInt86 (ThunkContext, Legacy8259, 0x13, &Regs); + + if (CarryFlag != 0) { + DEBUG ((DEBUG_INFO, "OLB: Failed to reset BIOS disk %u, error 0x%X\n", DriveNumber, Regs.H.AL)); + if (Regs.H.AL == BIOS_RESET_FAILED) { + Regs.H.AH = 0x00; + Regs.H.DL = DriveNumber; + CarryFlag = OcLegacyThunkBiosInt86 (ThunkContext, Legacy8259, 0x13, &Regs); + if (CarryFlag != 0) { + DEBUG ((DEBUG_INFO, "OLB: Failed to reset BIOS disk %u, error 0x%X\n", DriveNumber, Regs.H.AH)); + return EFI_DEVICE_ERROR; + } + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +BiosDiskExtensionsSupported ( + IN THUNK_CONTEXT *ThunkContext, + IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, + IN UINT8 DriveNumber + ) +{ + INTN CarryFlag; + IA32_REGISTER_SET Regs; + + ZeroMem (&Regs, sizeof (IA32_REGISTER_SET)); + + Regs.H.AH = 0x41; + Regs.X.BX = 0x55aa; + Regs.H.DL = DriveNumber; + CarryFlag = OcLegacyThunkBiosInt86 (ThunkContext, Legacy8259, 0x13, &Regs); + + if ((CarryFlag != 0) || (Regs.X.BX != 0xaa55)) { + return EFI_UNSUPPORTED; + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +BiosDiskReadExtSectors ( + IN THUNK_CONTEXT *ThunkContext, + IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, + IN DEVICE_ADDRESS_PACKET *DeviceAddressPacket, + IN UINT8 DriveNumber, + IN UINT64 Lba, + IN UINT8 NumSectors, + IN OUT UINT8 *Buffer + ) +{ + INTN CarryFlag; + IA32_REGISTER_SET Regs; + + ZeroMem (&Regs, sizeof (IA32_REGISTER_SET)); + + DeviceAddressPacket->PacketSizeInBytes = sizeof (*DeviceAddressPacket); + DeviceAddressPacket->Zero = 0; + DeviceAddressPacket->NumberOfBlocks = NumSectors; + DeviceAddressPacket->Zero2 = 0; + DeviceAddressPacket->SegOffset = (UINT32)LShiftU64 (RShiftU64 ((UINTN)Buffer, 4), 16); + DeviceAddressPacket->Lba = Lba; + + Regs.H.AH = 0x42; + Regs.H.DL = DriveNumber; + Regs.X.SI = EFI_OFFSET (DeviceAddressPacket); + Regs.E.DS = EFI_SEGMENT (DeviceAddressPacket); + CarryFlag = OcLegacyThunkBiosInt86 (ThunkContext, Legacy8259, 0x13, &Regs); + + if (CarryFlag != 0) { + return EFI_DEVICE_ERROR; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +InternalGetBiosDiskAddress ( + IN THUNK_CONTEXT *ThunkContext, + IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, + IN EFI_HANDLE DiskHandle, + OUT UINT8 *DriveAddress + ) +{ + EFI_STATUS Status; + OC_DISK_CONTEXT DiskContext; + UINT8 DriveAddr; + EFI_PHYSICAL_ADDRESS DeviceAddressPacketAddress; + DEVICE_ADDRESS_PACKET *DeviceAddressPacket; + UINT8 *BiosBuffer; + UINTN BiosBufferPages; + UINT32 BiosCrc32; + UINT8 *DiskBuffer; + UINTN DiskBufferSize; + UINT32 DiskCrc32; + BOOLEAN MatchedDisk; + + // + // Read sectors from EFI disk device. + // + Status = OcDiskInitializeContext (&DiskContext, DiskHandle, TRUE); + if (EFI_ERROR (Status)) { + return Status; + } + + DiskBufferSize = ALIGN_VALUE (BIOS_DISK_CHECK_BUFFER_SECTOR_COUNT * MBR_SIZE, DiskContext.BlockSize); + DiskBuffer = AllocatePool (DiskBufferSize); + if (DiskBuffer == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = OcDiskRead ( + &DiskContext, + 0, + DiskBufferSize, + DiskBuffer + ); + if (EFI_ERROR (Status)) { + FreePool (DiskBuffer); + return Status; + } + + gBS->CalculateCrc32 ( + DiskBuffer, + BIOS_DISK_CHECK_BUFFER_SECTOR_COUNT * MBR_SIZE, + &DiskCrc32 + ); + DEBUG ((DEBUG_INFO, "OLB: EFI disk CRC32: 0x%X\n", DiskCrc32)); + + // + // Allocate low memory buffer for disk reads. + // + DeviceAddressPacketAddress = (SIZE_1MB - 1); + BiosBufferPages = EFI_SIZE_TO_PAGES (sizeof (*DeviceAddressPacket) + (BIOS_DISK_CHECK_BUFFER_SECTOR_COUNT * MBR_SIZE)) + 1; + Status = gBS->AllocatePages ( + AllocateMaxAddress, + EfiBootServicesData, + BiosBufferPages, + &DeviceAddressPacketAddress + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OLB: Failure allocating low memory packet for BIOS disk read - %r\n", Status)); + FreePool (DiskBuffer); + return Status; + } + + DeviceAddressPacket = (DEVICE_ADDRESS_PACKET *)(UINTN)DeviceAddressPacketAddress; + BiosBuffer = (UINT8 *)(UINTN)DeviceAddressPacketAddress + 0x200; + + // + // Read sectors from each BIOS disk. + // Compare against sectors from EFI disk to determine BIOS disk address. + // + MatchedDisk = FALSE; + for (DriveAddr = 0x80; DriveAddr < 0x88; DriveAddr++) { + DEBUG ((DEBUG_INFO, "OLB: Reading BIOS drive 0x%X\n", DriveAddr)); + + // + // Reset disk and verify INT13H extensions are supported. + // + Status = BiosDiskReset (ThunkContext, Legacy8259, DriveAddr); + if (EFI_ERROR (Status)) { + continue; + } + + Status = BiosDiskExtensionsSupported (ThunkContext, Legacy8259, DriveAddr); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Read first 4 sectors from disk. + // + Status = BiosDiskReadExtSectors ( + ThunkContext, + Legacy8259, + DeviceAddressPacket, + DriveAddr, + 0, + BIOS_DISK_CHECK_BUFFER_SECTOR_COUNT, + BiosBuffer + ); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Calculate CRC32 of BIOS disk sectors. + // + gBS->CalculateCrc32 ( + BiosBuffer, + BIOS_DISK_CHECK_BUFFER_SECTOR_COUNT * MBR_SIZE, + &BiosCrc32 + ); + DEBUG ((DEBUG_INFO, "OLB: BIOS disk CRC32: 0x%X\n", BiosCrc32)); + + if (BiosCrc32 == DiskCrc32) { + DEBUG ((DEBUG_INFO, "OLB: Matched BIOS disk address 0x%X\n", DriveAddr)); + + MatchedDisk = TRUE; + *DriveAddress = DriveAddr; + break; + } + } + + FreePool (DiskBuffer); + gBS->FreePages ( + DeviceAddressPacketAddress, + BiosBufferPages + ); + + return MatchedDisk ? EFI_SUCCESS : EFI_NOT_FOUND; +} diff --git a/Platform/OpenLegacyBoot/LegacyBootInternal.h b/Platform/OpenLegacyBoot/LegacyBootInternal.h new file mode 100644 index 00000000..df90c24b --- /dev/null +++ b/Platform/OpenLegacyBoot/LegacyBootInternal.h @@ -0,0 +1,76 @@ +/** @file + Copyright (C) 2023, Goldfish64. All rights reserved.
+ SPDX-License-Identifier: BSD-3-Clause +**/ + +#ifndef LEGACY_BOOT_INTERNAL_H +#define LEGACY_BOOT_INTERNAL_H + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/** + Legacy operating system type. +**/ +typedef enum OC_LEGACY_OS_TYPE_ { + OcLegacyOsTypeNone, + OcLegacyOsTypeWindowsNtldr, + OcLegacyOsTypeWindowsBootmgr, + OcLegacyOsTypeIsoLinux +} OC_LEGACY_OS_TYPE; + +EFI_STATUS +InternalGetBiosDiskAddress ( + IN THUNK_CONTEXT *ThunkContext, + IN EFI_LEGACY_8259_PROTOCOL *Legacy8259, + IN EFI_HANDLE DiskHandle, + OUT UINT8 *DriveNumber + ); + +EFI_STATUS +InternalIsLegacyInterfaceSupported ( + OUT BOOLEAN *IsAppleInterfaceSupported + ); + +EFI_STATUS +InternalSetBootCampHDPath ( + IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath + ); + +EFI_STATUS +InternalLoadAppleLegacyInterface ( + IN EFI_HANDLE ParentImageHandle, + OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath, + OUT EFI_HANDLE *ImageHandle + ); + +OC_LEGACY_OS_TYPE +InternalGetPartitionLegacyOsType ( + IN EFI_HANDLE PartitionHandle, + IN BOOLEAN IsCdRomSupported + ); + +EFI_STATUS +InternalLoadLegacyPbr ( + IN EFI_DEVICE_PATH_PROTOCOL *PartitionPath + ); + +#endif // LEGACY_BOOT_INTERNAL_H diff --git a/Platform/OpenLegacyBoot/LegacyBootSupport.c b/Platform/OpenLegacyBoot/LegacyBootSupport.c new file mode 100644 index 00000000..412908cb --- /dev/null +++ b/Platform/OpenLegacyBoot/LegacyBootSupport.c @@ -0,0 +1,502 @@ +/** @file + Copyright (C) 2023, Goldfish64. All rights reserved.
+ SPDX-License-Identifier: BSD-3-Clause +**/ + +#include "LegacyBootInternal.h" + +THUNK_CONTEXT mThunkContext; + +// +// PIWG firmware media device path for Apple legacy interface. +// FwFile(2B0585EB-D8B8-49A9-8B8CE21B01AEF2B7) +// +STATIC CONST UINT8 AppleLegacyInterfaceMediaDevicePathData[] = { + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00 +}; +STATIC CONST EFI_DEVICE_PATH_PROTOCOL *AppleLegacyInterfaceMediaDevicePathPath = (EFI_DEVICE_PATH_PROTOCOL *)AppleLegacyInterfaceMediaDevicePathData; + +#define MAX_APPLE_LEGACY_DEVICE_PATHS 16 + +STATIC +BOOLEAN +CheckLegacySignature ( + IN CONST CHAR8 *SignatureStr, + IN UINT8 *Buffer, + IN UINTN BufferSize + ) +{ + UINT32 Offset; + + Offset = 0; + + return FindPattern ( + (CONST UINT8 *)SignatureStr, + NULL, + (CONST UINT32)AsciiStrLen (SignatureStr), + Buffer, + (UINT32)BufferSize, + &Offset + ); +} + +STATIC +EFI_STATUS +ScanAppleLegacyInterfacePaths ( + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePaths, + IN UINTN MaxDevicePaths + ) +{ + EFI_STATUS Status; + UINTN NoHandles; + EFI_HANDLE *Handles; + UINTN HandleIndex; + UINTN PathCount; + UINTN PathIndex; + BOOLEAN DevicePathExists; + + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + + MaxDevicePaths--; + PathCount = 0; + + // + // Get all LoadedImage protocol handles. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiLoadedImageProtocolGuid, + NULL, + &NoHandles, + &Handles + ); + if (EFI_ERROR (Status)) { + return Status; + } + + for (HandleIndex = 0; HandleIndex < NoHandles && PathCount < MaxDevicePaths; HandleIndex++) { + Status = gBS->HandleProtocol ( + Handles[HandleIndex], + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImage + ); + if (EFI_ERROR (Status)) { + continue; + } + + Status = gBS->HandleProtocol ( + LoadedImage->DeviceHandle, + &gEfiDevicePathProtocolGuid, + (VOID **)&DevicePath + ); + if (EFI_ERROR (Status)) { + continue; + } + + // + // Legacy boot interface will be behind a memory range node. + // + if ( (DevicePathType (DevicePath) != HARDWARE_DEVICE_PATH) + || (DevicePathSubType (DevicePath) != HW_MEMMAP_DP)) + { + continue; + } + + // + // Ensure we don't add a duplicate path. + // + DevicePathExists = FALSE; + for (PathIndex = 0; PathIndex < PathCount; PathIndex++) { + if (DevicePathNodeLength (DevicePath) != DevicePathNodeLength (DevicePaths[PathIndex])) { + continue; + } + + if (CompareMem (DevicePath, DevicePaths[PathIndex], DevicePathNodeLength (DevicePath))) { + DevicePathExists = TRUE; + break; + } + } + + if (DevicePathExists) { + continue; + } + + DevicePaths[PathCount++] = AppendDevicePath (DevicePath, AppleLegacyInterfaceMediaDevicePathPath); + } + + FreePool (Handles); + + DevicePaths[PathCount] = NULL; + return EFI_SUCCESS; +} + +EFI_STATUS +InternalIsLegacyInterfaceSupported ( + OUT BOOLEAN *IsAppleInterfaceSupported + ) +{ + EFI_STATUS Status; + EFI_LEGACY_8259_PROTOCOL *Legacy8259; + + ASSERT (IsAppleInterfaceSupported != NULL); + + // + // Apple legacy boot interface is only available on Apple platforms. + // Use legacy 16-bit thunks on legacy PC platforms. + // + if (OcStriCmp (L"Apple", gST->FirmwareVendor) == 0) { + *IsAppleInterfaceSupported = TRUE; + return EFI_SUCCESS; + } else { + Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **)&Legacy8259); + if (!EFI_ERROR (Status) && (Legacy8259 != NULL)) { + *IsAppleInterfaceSupported = FALSE; + return EFI_SUCCESS; + } + } + + return EFI_UNSUPPORTED; +} + +EFI_STATUS +InternalSetBootCampHDPath ( + IN EFI_DEVICE_PATH_PROTOCOL *HdDevicePath + ) +{ + EFI_STATUS Status; + EFI_HANDLE DiskHandle; + EFI_HANDLE PartitionHandle; + UINT8 PartitionIndex; + EFI_DEVICE_PATH_PROTOCOL *WholeDiskPath; + + WholeDiskPath = OcDiskGetDevicePath (HdDevicePath); + if (WholeDiskPath == NULL) { + return EFI_INVALID_PARAMETER; + } + + DebugPrintDevicePath (DEBUG_INFO, "OLB: Legacy disk device path", WholeDiskPath); + + // + // Mark target partition as active. + // + DiskHandle = OcPartitionGetDiskHandle (HdDevicePath); + if (DiskHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + PartitionHandle = OcPartitionGetPartitionHandle (HdDevicePath); + if (PartitionHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = OcDiskGetMbrPartitionIndex (PartitionHandle, &PartitionIndex); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = OcDiskMarkMbrPartitionActive (DiskHandle, PartitionIndex); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Set BootCampHD variable pointing to target disk. + // + return gRT->SetVariable ( + APPLE_BOOT_CAMP_HD_VARIABLE_NAME, + &gAppleBootVariableGuid, + EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE, + GetDevicePathSize (WholeDiskPath), + WholeDiskPath + ); +} + +EFI_STATUS +InternalLoadAppleLegacyInterface ( + IN EFI_HANDLE ParentImageHandle, + OUT EFI_DEVICE_PATH_PROTOCOL **ImageDevicePath, + OUT EFI_HANDLE *ImageHandle + ) +{ + EFI_STATUS Status; + EFI_DEVICE_PATH_PROTOCOL **LegacyDevicePaths; + CHAR16 *UnicodeDevicePath; + UINTN Index; + + // + // Get list of possible locations for Apple legacy interface and attempt to load. + // + LegacyDevicePaths = AllocateZeroPool (sizeof (*LegacyDevicePaths) * MAX_APPLE_LEGACY_DEVICE_PATHS); + if (LegacyDevicePaths == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + Status = ScanAppleLegacyInterfacePaths (LegacyDevicePaths, MAX_APPLE_LEGACY_DEVICE_PATHS); + if (!EFI_ERROR (Status)) { + for (Index = 0; LegacyDevicePaths[Index] != NULL; Index++) { + Status = gBS->LoadImage ( + FALSE, + ParentImageHandle, + LegacyDevicePaths[Index], + NULL, + 0, + ImageHandle + ); + if (Status != EFI_NOT_FOUND) { + *ImageDevicePath = LegacyDevicePaths[Index]; + + DEBUG_CODE_BEGIN (); + + UnicodeDevicePath = ConvertDevicePathToText (*ImageDevicePath, FALSE, FALSE); + DEBUG (( + DEBUG_INFO, + "OLB: Loaded Apple legacy interface at dp %s - %r\n", + UnicodeDevicePath != NULL ? UnicodeDevicePath : L"", + Status + )); + if (UnicodeDevicePath != NULL) { + FreePool (UnicodeDevicePath); + } + + DEBUG_CODE_END (); + + break; + } + } + } + + FreePool (LegacyDevicePaths); + + return Status; +} + +OC_LEGACY_OS_TYPE +InternalGetPartitionLegacyOsType ( + IN EFI_HANDLE PartitionHandle, + IN BOOLEAN IsCdRomSupported + ) +{ + EFI_STATUS Status; + UINT8 *Buffer; + UINTN BufferSize; + MASTER_BOOT_RECORD *Mbr; + EFI_DEVICE_PATH_PROTOCOL *DevicePath; + EFI_HANDLE DiskHandle; + OC_LEGACY_OS_TYPE LegacyOsType; + + ASSERT (PartitionHandle != NULL); + + DevicePath = DevicePathFromHandle (PartitionHandle); + if (DevicePath == NULL) { + return OcLegacyOsTypeNone; + } + + DiskHandle = OcPartitionGetDiskHandle (DevicePath); + if (DiskHandle == NULL) { + return OcLegacyOsTypeNone; + } + + // + // For CD devices, validate El-Torito structures. + // For hard disk and USB devices, validate MBR and PBR of target partition. + // + if (OcIsDiskCdRom (DevicePath)) { + if (!IsCdRomSupported) { + DEBUG ((DEBUG_INFO, "OLB: CD-ROM boot not supported on this platform\n")); + return OcLegacyOsTypeNone; + } + + DebugPrintDevicePath (DEBUG_INFO, "OLB: Reading El-Torito for CDROM", DevicePath); + Status = OcDiskReadElTorito (DevicePath, &Buffer, &BufferSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OLB: Failed reading El-Torito - %r\n", Status)); + return OcLegacyOsTypeNone; + } + } else { + DebugPrintDevicePath (DEBUG_INFO, "OLB: Reading MBR for parent disk", DevicePath); + Mbr = OcGetDiskMbrTable (DiskHandle, TRUE); + if (Mbr == NULL) { + DEBUG ((DEBUG_INFO, "OLB: Disk does not contain a valid MBR\n")); + return OcLegacyOsTypeNone; + } + + FreePool (Mbr); + + // + // Retrieve PBR for partition. + // + DebugPrintDevicePath (DEBUG_INFO, "OLB: Reading PBR for partition", DevicePath); + Mbr = OcGetDiskMbrTable (PartitionHandle, FALSE); + if (Mbr == NULL) { + DEBUG ((DEBUG_INFO, "OLB: Partition does not contain a valid PBR\n")); + return OcLegacyOsTypeNone; + } + + Buffer = (UINT8 *)Mbr; + BufferSize = sizeof (*Mbr); + } + + DebugPrintHexDump (DEBUG_INFO, "OLB: PbrHEX", Buffer, BufferSize); + + // + // Validate sector contents and check for known signatures + // indicating the partition is bootable. + // + if (CheckLegacySignature ("BOOTMGR", Buffer, BufferSize)) { + LegacyOsType = OcLegacyOsTypeWindowsBootmgr; + } else if (CheckLegacySignature ("NTLDR", Buffer, BufferSize)) { + LegacyOsType = OcLegacyOsTypeWindowsNtldr; + } else if ( CheckLegacySignature ("ISOLINUX", Buffer, BufferSize) + || CheckLegacySignature ("isolinux", Buffer, BufferSize)) + { + LegacyOsType = OcLegacyOsTypeIsoLinux; + } else { + LegacyOsType = OcLegacyOsTypeNone; + DEBUG ((DEBUG_INFO, "OLB: Unknown legacy bootsector signature\n")); + } + + FreePool (Buffer); + + return LegacyOsType; +} + +EFI_STATUS +InternalLoadLegacyPbr ( + IN EFI_DEVICE_PATH_PROTOCOL *PartitionPath + ) +{ + EFI_STATUS Status; + EFI_HANDLE DiskHandle; + EFI_HANDLE PartitionHandle; + MASTER_BOOT_RECORD *Mbr; + MASTER_BOOT_RECORD *Pbr; + UINT8 PartitionIndex; + UINT8 BiosDiskAddress; + + IA32_REGISTER_SET Regs; + MASTER_BOOT_RECORD *MbrPtr = (MASTER_BOOT_RECORD *)0x0600; + MASTER_BOOT_RECORD *PbrPtr = (MASTER_BOOT_RECORD *)0x7C00; + EFI_LEGACY_8259_PROTOCOL *Legacy8259; + + // + // Locate Legacy8259 protocol. + // + Status = gBS->LocateProtocol ( + &gEfiLegacy8259ProtocolGuid, + NULL, + (VOID **)&Legacy8259 + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OLB: Could not locate Legacy8259 protocol\n")); + return Status; + } + + // + // Retrieve the PBR from partition and partition index. + // + PartitionHandle = OcPartitionGetPartitionHandle (PartitionPath); + if (PartitionHandle == NULL) { + DEBUG ((DEBUG_INFO, "OLB: Could not locate partition handle\n")); + return EFI_INVALID_PARAMETER; + } + + Pbr = OcGetDiskMbrTable (PartitionHandle, FALSE); + if (Pbr == NULL) { + DEBUG ((DEBUG_INFO, "OLB: Partition does not contain a valid PBR\n")); + return EFI_INVALID_PARAMETER; + } + + Status = OcDiskGetMbrPartitionIndex (PartitionHandle, &PartitionIndex); + if (EFI_ERROR (Status)) { + FreePool (Pbr); + return Status; + } + + DebugPrintHexDump (DEBUG_INFO, "OLB: PbrHEX", (UINT8 *)Pbr, sizeof (*Pbr)); + + // + // Retrieve MBR from disk. + // + DiskHandle = OcPartitionGetDiskHandle (PartitionPath); + if (DiskHandle == NULL) { + FreePool (Pbr); + return EFI_INVALID_PARAMETER; + } + + Mbr = OcGetDiskMbrTable (DiskHandle, TRUE); + if (Mbr == NULL) { + DEBUG ((DEBUG_INFO, "OLB: Disk does not contain a valid MBR\n")); + FreePool (Pbr); + return EFI_INVALID_PARAMETER; + } + + DebugPrintHexDump (DEBUG_INFO, "OLB: MbrHEX", (UINT8 *)Mbr, sizeof (*Mbr)); + + // + // Create and initialize thunk structures. + // + Status = OcLegacyThunkInitializeBiosIntCaller (&mThunkContext); + if (EFI_ERROR (Status)) { + FreePool (Pbr); + FreePool (Mbr); + return Status; + } + + Status = OcLegacyThunkInitializeInterruptRedirection (Legacy8259); + if (EFI_ERROR (Status)) { + FreePool (Pbr); + FreePool (Mbr); + return Status; + } + + // + // Determine BIOS disk number. + // + Status = InternalGetBiosDiskAddress ( + &mThunkContext, + Legacy8259, + DiskHandle, + &BiosDiskAddress + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OLB: Disk address could not be determined\n")); + FreePool (Pbr); + FreePool (Mbr); + return Status; + } + + // + // Copy MBR and PBR to low memory locations for booting. + // + CopyMem (PbrPtr, Pbr, sizeof (*Pbr)); + CopyMem (MbrPtr, Mbr, sizeof (*Mbr)); + + DebugPrintHexDump (DEBUG_INFO, "OLB: PbrPtr", (UINT8 *)PbrPtr, sizeof (*PbrPtr)); + + OcLegacyThunkDisconnectEfiGraphics (); + + // + // Thunk to real mode and invoke legacy boot sector. + // If successful, this function will not return. + // + ZeroMem (&Regs, sizeof (Regs)); + + Regs.H.DL = BiosDiskAddress; + Regs.X.SI = (UINT16)(UINTN)&MbrPtr->Partition[PartitionIndex]; + OcLegacyThunkFarCall86 ( + &mThunkContext, + Legacy8259, + 0, + 0x7c00, + &Regs, + NULL, + 0 + ); + + DEBUG ((DEBUG_WARN, "OLB: Failure calling legacy boot sector\n")); + + return EFI_INVALID_PARAMETER; +} diff --git a/Platform/OpenLegacyBoot/OpenLegacyBoot.c b/Platform/OpenLegacyBoot/OpenLegacyBoot.c new file mode 100644 index 00000000..1a157a2f --- /dev/null +++ b/Platform/OpenLegacyBoot/OpenLegacyBoot.c @@ -0,0 +1,535 @@ +/** @file + Legacy boot driver. + + Copyright (c) 2023, Goldfish64. All rights reserved.
+ SPDX-License-Identifier: BSD-3-Clause +**/ + +#include "LegacyBootInternal.h" + +#include + +STATIC EFI_HANDLE mImageHandle; +STATIC BOOLEAN mIsAppleInterfaceSupported; + +STATIC OC_FLEX_ARRAY *mHiddenDevicePaths; + +// +// Fallback PIWG firmware media device path for Apple legacy interface. +// MemoryMapped(0xB,0xFFE00000,0xFFF9FFFF)/FvFile(2B0585EB-D8B8-49A9-8B8C-E21B01AEF2B7) +// +STATIC CONST UINT8 AppleLegacyInterfaceFallbackDevicePathData[] = { + 0x01, 0x03, 0x18, 0x00, 0x0B, 0x00, 0x00, 0x00, + 0x00, 0x00, 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0xFF, 0xFF, 0xF9, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x04, 0x06, 0x14, 0x00, 0xEB, 0x85, 0x05, 0x2B, + 0xB8, 0xD8, 0xA9, 0x49, 0x8B, 0x8C, 0xE2, 0x1B, + 0x01, 0xAE, 0xF2, 0xB7, 0x7F, 0xFF, 0x04, 0x00 +}; +STATIC CONST EFI_DEVICE_PATH_PROTOCOL *AppleLegacyInterfaceFallbackDevicePathPath = (EFI_DEVICE_PATH_PROTOCOL *)AppleLegacyInterfaceFallbackDevicePathData; + +STATIC +CHAR8 * +GetLegacyEntryName ( + OC_LEGACY_OS_TYPE LegacyOsType + ) +{ + return AllocateCopyPool (L_STR_SIZE ("Windows (legacy)"), "Windows (legacy)"); +} + +STATIC +CHAR8 * +GetLegacyEntryFlavour ( + OC_LEGACY_OS_TYPE LegacyOsType + ) +{ + return AllocateCopyPool (L_STR_SIZE (OC_FLAVOUR_WINDOWS), OC_FLAVOUR_WINDOWS); +} + +STATIC +CHAR8 * +LoadAppleDiskLabel ( + IN OUT OC_PICKER_CONTEXT *PickerContext, + IN EFI_HANDLE DiskHandle + ) +{ + EFI_STATUS Status; + CHAR8 *DiskLabel; + EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *FileSystem; + + DiskLabel = NULL; + if ((PickerContext->PickerAttributes & OC_ATTR_USE_DISK_LABEL_FILE) != 0) { + Status = gBS->HandleProtocol ( + DiskHandle, + &gEfiSimpleFileSystemProtocolGuid, + (VOID **)&FileSystem + ); + if (EFI_ERROR (Status)) { + return NULL; + } + + DiskLabel = OcReadFile (FileSystem, L".contentDetails", NULL, 0); + if (DiskLabel == NULL) { + DiskLabel = OcReadFile (FileSystem, L".disk_label.contentDetails", NULL, 0); + } + + if (DiskLabel == NULL) { + DEBUG ((DEBUG_INFO, "OLB: %s %s not present\n", L".contentDetails", L".disk_label.contentDetails")); + } else { + DEBUG ((DEBUG_INFO, "OLB: Found disk label '%a'\n", DiskLabel)); + } + } + + return DiskLabel; +} + +STATIC +VOID +FreePickerEntry ( + IN OC_PICKER_ENTRY *Entry + ) +{ + ASSERT (Entry != NULL); + + if (Entry == NULL) { + return; + } + + if (Entry->Id != NULL) { + FreePool ((CHAR8 *)Entry->Id); + } + + if (Entry->Name != NULL) { + FreePool ((CHAR8 *)Entry->Name); + } + + if (Entry->Flavour != NULL) { + FreePool ((CHAR8 *)Entry->Flavour); + } +} + +STATIC +EFI_STATUS +ExternalSystemActionDoLegacyBoot ( + IN OUT OC_PICKER_CONTEXT *PickerContext, + IN EFI_DEVICE_PATH_PROTOCOL *DevicePath + ) +{ + EFI_STATUS Status; + EFI_HANDLE DiskHandle; + EFI_HANDLE LoadedImageHandle; + EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + BOOLEAN IsExternal; + CONST CHAR8 *AppleBootArg; + + // + // Set BootCampHD to desired disk Device Path for non-CD devices. + // + if (!OcIsDiskCdRom (DevicePath)) { + Status = InternalSetBootCampHDPath (DevicePath); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OLB: Failure while setting BootCampHD variable - %r\n", Status)); + return Status; + } + } + + // + // Load and start legacy OS. + // + // On Macs, use the Apple legacy interface. + // On other systems, use the Legacy8259 protocol. + // + DebugPrintDevicePath (DEBUG_INFO, "OLB: Legacy device path", DevicePath); + if (mIsAppleInterfaceSupported) { + DiskHandle = OcPartitionGetPartitionHandle (DevicePath); + if (DiskHandle == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = InternalLoadAppleLegacyInterface ( + mImageHandle, + &LoadedImageDevicePath, + &LoadedImageHandle + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OLB: Failure while loading Apple legacy interface - %r\n", Status)); + return Status; + } + + // + // Specify boot device type argument on loaded image. + // + Status = gBS->HandleProtocol ( + LoadedImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImage + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OLB: Failure while loading Apple legacy interface - %r\n", Status)); + gBS->UnloadImage (LoadedImageHandle); + return Status; + } + + LoadedImage->LoadOptionsSize = 0; + LoadedImage->LoadOptions = NULL; + + OcGetDevicePolicyType (DiskHandle, &IsExternal); + + if (OcIsDiskCdRom (DevicePath)) { + AppleBootArg = "CD"; + } else if (IsExternal) { + AppleBootArg = "USB"; + } else { + AppleBootArg = "HD"; + } + + OcAppendArgumentsToLoadedImage ( + LoadedImage, + &AppleBootArg, + 1, + TRUE + ); + DEBUG ((DEBUG_INFO, "OLB: Apple legacy interface args <%s>\n", LoadedImage->LoadOptions)); + + Status = gBS->StartImage (LoadedImageHandle, NULL, NULL); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OLB: Failure while starting Apple legacy interface - %r\n", Status)); + gBS->UnloadImage (LoadedImageHandle); + return Status; + } + } else { + Status = InternalLoadLegacyPbr (DevicePath); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OLB: Failure while starting legacy PBR interface - %r\n", Status)); + return Status; + } + } + + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +ExternalSystemGetDevicePath ( + IN OUT OC_PICKER_CONTEXT *PickerContext, + IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath + ) +{ + EFI_STATUS Status; + EFI_HANDLE LoadedImageHandle; + EFI_DEVICE_PATH_PROTOCOL *LoadedImageDevicePath; + EFI_DEVICE_PATH_PROTOCOL *AppleLoaderDevicePath; + + // + // Set BootCampHD to desired disk Device Path for non-CD devices. + // + if (!OcIsDiskCdRom (*DevicePath)) { + Status = InternalSetBootCampHDPath (*DevicePath); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OLB: Failure while setting BootCampHD variable - %r\n", Status)); + return Status; + } + } + + // + // Locate Apple legacy interface loader. + // + // On Macs, use the Apple legacy interface and set BootCampHD. + // On other systems, use a default placeholder path. + // + DebugPrintDevicePath (DEBUG_INFO, "OLB: Legacy device path", *DevicePath); + if (mIsAppleInterfaceSupported) { + Status = InternalLoadAppleLegacyInterface ( + mImageHandle, + &LoadedImageDevicePath, + &LoadedImageHandle + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OLB: Failure while loading Apple legacy interface - %r\n", Status)); + return Status; + } + + gBS->UnloadImage (LoadedImageHandle); + + AppleLoaderDevicePath = DuplicateDevicePath (LoadedImageDevicePath); + } else { + AppleLoaderDevicePath = DuplicateDevicePath (AppleLegacyInterfaceFallbackDevicePathPath); + } + + if (AppleLoaderDevicePath == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *DevicePath = AppleLoaderDevicePath; + return EFI_SUCCESS; +} + +STATIC +EFI_STATUS +EFIAPI +OcGetLegacyBootEntries ( + IN OUT OC_PICKER_CONTEXT *PickerContext, + IN CONST EFI_HANDLE Device OPTIONAL, + OUT OC_PICKER_ENTRY **Entries, + OUT UINTN *NumEntries + ) +{ + EFI_STATUS Status; + UINTN NoHandles; + EFI_HANDLE *Handles; + UINTN HandleIndex; + UINTN DevicePathIndex; + BOOLEAN SkipHiddenDevice; + UINT32 ScanPolicy; + BOOLEAN IsExternal; + + CHAR16 *UnicodeDevicePath; + CHAR8 *AsciiDevicePath; + UINTN AsciiDevicePathSize; + CHAR16 **HiddenUnicodeDevicePath; + + EFI_HANDLE BlockDeviceHandle; + EFI_DEVICE_PATH_PROTOCOL *BlockDevicePath; + OC_LEGACY_OS_TYPE LegacyOsType; + OC_FLEX_ARRAY *FlexPickerEntries; + OC_PICKER_ENTRY *PickerEntry; + + ASSERT (PickerContext != NULL); + ASSERT (Entries != NULL); + ASSERT (NumEntries != NULL); + + // + // Custom entries only. + // + if (Device != NULL) { + return EFI_NOT_FOUND; + } + + FlexPickerEntries = OcFlexArrayInit (sizeof (OC_PICKER_ENTRY), (OC_FLEX_ARRAY_FREE_ITEM)FreePickerEntry); + if (FlexPickerEntries == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Get all Block I/O handles. + // + Status = gBS->LocateHandleBuffer ( + ByProtocol, + &gEfiBlockIoProtocolGuid, + NULL, + &NoHandles, + &Handles + ); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_INFO, "OLB: Failed to get Block I/O handles - %r\n", Status)); + OcFlexArrayFree (&FlexPickerEntries); + return Status; + } + + for (HandleIndex = 0; HandleIndex < NoHandles; HandleIndex++) { + BlockDeviceHandle = Handles[HandleIndex]; + + // + // If device type locking is set and this device is not allowed, + // skip device. + // + ScanPolicy = OcGetDevicePolicyType (BlockDeviceHandle, &IsExternal); + if (((PickerContext->ScanPolicy & OC_SCAN_DEVICE_LOCK) != 0) && ((ScanPolicy & PickerContext->ScanPolicy) == 0)) { + continue; + } + + BlockDevicePath = DevicePathFromHandle (BlockDeviceHandle); + if (BlockDevicePath == NULL) { + DEBUG ((DEBUG_INFO, "OLB: Could not find Device Path for block device\n")); + continue; + } + + // + // Device Path will be used as ID and is required for default entry matching. + // + UnicodeDevicePath = ConvertDevicePathToText (BlockDevicePath, FALSE, FALSE); + if (UnicodeDevicePath == NULL) { + OcFlexArrayFree (&FlexPickerEntries); + return EFI_OUT_OF_RESOURCES; + } + + // + // Skip device if on hidden list. + // + if (mHiddenDevicePaths != NULL) { + SkipHiddenDevice = FALSE; + for (DevicePathIndex = 0; DevicePathIndex < mHiddenDevicePaths->Count; DevicePathIndex++) { + HiddenUnicodeDevicePath = (CHAR16 **)OcFlexArrayItemAt (mHiddenDevicePaths, DevicePathIndex); + ASSERT (HiddenUnicodeDevicePath != NULL); + + if (StrCmp (UnicodeDevicePath, *HiddenUnicodeDevicePath) == 0) { + DEBUG ((DEBUG_INFO, "OLB: Skipping hidden device %s\n", *HiddenUnicodeDevicePath)); + SkipHiddenDevice = TRUE; + break; + } + } + + if (SkipHiddenDevice) { + FreePool (UnicodeDevicePath); + continue; + } + } + + // + // Detect legacy OS type. + // + LegacyOsType = InternalGetPartitionLegacyOsType (BlockDeviceHandle, mIsAppleInterfaceSupported); + if (LegacyOsType == OcLegacyOsTypeNone) { + FreePool (UnicodeDevicePath); + continue; + } + + // + // Create and add picker entry to entries. + // + PickerEntry = OcFlexArrayAddItem (FlexPickerEntries); + if (PickerEntry == NULL) { + FreePool (UnicodeDevicePath); + OcFlexArrayFree (&FlexPickerEntries); + return EFI_OUT_OF_RESOURCES; + } + + AsciiDevicePathSize = (StrLen (UnicodeDevicePath) + 1) * sizeof (CHAR8); + AsciiDevicePath = AllocatePool (AsciiDevicePathSize); + if (AsciiDevicePath == NULL) { + FreePool (UnicodeDevicePath); + OcFlexArrayFree (&FlexPickerEntries); + return EFI_OUT_OF_RESOURCES; + } + + Status = UnicodeStrToAsciiStrS (UnicodeDevicePath, AsciiDevicePath, AsciiDevicePathSize); + FreePool (UnicodeDevicePath); + if (EFI_ERROR (Status)) { + FreePool (AsciiDevicePath); + OcFlexArrayFree (&FlexPickerEntries); + return Status; + } + + PickerEntry->Name = LoadAppleDiskLabel (PickerContext, BlockDeviceHandle); + if (PickerEntry->Name == NULL) { + PickerEntry->Name = GetLegacyEntryName (LegacyOsType); + } + + PickerEntry->Id = AsciiDevicePath; + PickerEntry->Path = NULL; + PickerEntry->Arguments = NULL; + PickerEntry->Flavour = GetLegacyEntryFlavour (LegacyOsType); + PickerEntry->Tool = FALSE; + PickerEntry->TextMode = FALSE; + PickerEntry->RealPath = FALSE; + PickerEntry->External = IsExternal; + PickerEntry->ExternalSystemAction = ExternalSystemActionDoLegacyBoot; + PickerEntry->ExternalSystemGetDevicePath = ExternalSystemGetDevicePath; + PickerEntry->ExternalSystemDevicePath = BlockDevicePath; + + if ((PickerEntry->Name == NULL) || (PickerEntry->Flavour == NULL)) { + OcFlexArrayFree (&FlexPickerEntries); + return EFI_OUT_OF_RESOURCES; + } + } + + OcFlexArrayFreeContainer (&FlexPickerEntries, (VOID **)Entries, NumEntries); + + return EFI_SUCCESS; +} + +STATIC +VOID +EFIAPI +OcFreeLegacyBootEntries ( + IN OC_PICKER_ENTRY **Entries, + IN UINTN NumEntries + ) +{ + UINTN Index; + + ASSERT (Entries != NULL); + ASSERT (*Entries != NULL); + if ((Entries == NULL) || (*Entries == NULL)) { + return; + } + + for (Index = 0; Index < NumEntries; Index++) { + FreePickerEntry (&(*Entries)[Index]); + } + + FreePool (*Entries); + *Entries = NULL; +} + +STATIC +OC_BOOT_ENTRY_PROTOCOL + mLegacyBootEntryProtocol = { + OC_BOOT_ENTRY_PROTOCOL_REVISION, + OcGetLegacyBootEntries, + OcFreeLegacyBootEntries, + NULL +}; + +EFI_STATUS +EFIAPI +UefiMain ( + IN EFI_HANDLE ImageHandle, + IN EFI_SYSTEM_TABLE *SystemTable + ) +{ + EFI_STATUS Status; + EFI_LOADED_IMAGE_PROTOCOL *LoadedImage; + CHAR16 *DevicePathNames; + OC_FLEX_ARRAY *ParsedLoadOptions; + + Status = gBS->HandleProtocol ( + ImageHandle, + &gEfiLoadedImageProtocolGuid, + (VOID **)&LoadedImage + ); + if (EFI_ERROR (Status)) { + return Status; + } + + mImageHandle = ImageHandle; + mHiddenDevicePaths = NULL; + + Status = OcParseLoadOptions (LoadedImage, &ParsedLoadOptions); + if (!EFI_ERROR (Status)) { + OcParsedVarsGetUnicodeStr (ParsedLoadOptions, L"--hide-devices", &DevicePathNames); + if (DevicePathNames != NULL) { + mHiddenDevicePaths = OcStringSplit (DevicePathNames, L';', OcStringFormatUnicode); + if (mHiddenDevicePaths == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + } else { + if (Status != EFI_NOT_FOUND) { + return Status; + } + } + + Status = InternalIsLegacyInterfaceSupported (&mIsAppleInterfaceSupported); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_WARN, "OLB: Legacy boot interface is supported on this system\n")); + return Status; + } + + DEBUG ((DEBUG_INFO, "OLB: Apple legacy interface: %d\n", mIsAppleInterfaceSupported)); + + Status = gBS->InstallMultipleProtocolInterfaces ( + &ImageHandle, + &gOcBootEntryProtocolGuid, + &mLegacyBootEntryProtocol, + NULL + ); + + ASSERT_EFI_ERROR (Status); + if (EFI_ERROR (Status)) { + return Status; + } + + return EFI_SUCCESS; +} diff --git a/Platform/OpenLegacyBoot/OpenLegacyBoot.inf b/Platform/OpenLegacyBoot/OpenLegacyBoot.inf new file mode 100644 index 00000000..c553c39c --- /dev/null +++ b/Platform/OpenLegacyBoot/OpenLegacyBoot.inf @@ -0,0 +1,45 @@ +## @file +# Legacy boot entry protocol implementation. +# +# Copyright (C) 2023, Goldfish64. All rights reserved.
+# SPDX-License-Identifier: BSD-3-Clause +## + + +[Defines] + INF_VERSION = 0x00010005 + BASE_NAME = OpenLegacyBoot + ENTRY_POINT = UefiMain + FILE_GUID = 4BE5FC32-9434-4799-9F8F-ECD579025074 + MODULE_TYPE = UEFI_DRIVER + VERSION_STRING = 1.0 + +[Packages] + OpenCorePkg/OpenCorePkg.dec + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + OvmfPkg/OvmfPkg.dec + +[Guids] + gAppleLegacyLoadAppFileGuid ## SOMETIMES_CONSUMES + +[LibraryClasses] + DebugLib + OcBootManagementLib + OcFileLib + OcFlexArrayLib + OcLegacyThunkLib + SortLib + UefiBootServicesTableLib + UefiDriverEntryPoint + UefiLib + +[Protocols] + gOcBootEntryProtocolGuid ## PRODUCES + gEfiLegacy8259ProtocolGuid ## SOMETIMES_CONSUMES + +[Sources] + BiosDisk.c + LegacyBootInternal.h + LegacyBootSupport.c + OpenLegacyBoot.c diff --git a/build_oc.tool b/build_oc.tool index 3584982d..a336efc9 100755 --- a/build_oc.tool +++ b/build_oc.tool @@ -198,6 +198,7 @@ package() { "NvmExpressDxe.efi" "OpenCanopy.efi" "OpenHfsPlus.efi" + "OpenLegacyBoot.efi" "OpenLinuxBoot.efi" "OpenNtfsDxe.efi" "OpenPartitionDxe.efi"