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"