mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
Implement legacy OS booting support (#482)
This commit is contained in:
parent
2bbda9de78
commit
bb44e89add
@ -1322,6 +1322,7 @@
|
||||
<string>nvda_drv</string>
|
||||
<string>prev-lang:kbd</string>
|
||||
<string>backlight-level</string>
|
||||
<string>BootCampHD</string>
|
||||
</array>
|
||||
<key>8BE4DF61-93CA-11D2-AA0D-00E098032B8C</key>
|
||||
<array>
|
||||
|
||||
@ -1349,6 +1349,7 @@
|
||||
<string>nvda_drv</string>
|
||||
<string>prev-lang:kbd</string>
|
||||
<string>backlight-level</string>
|
||||
<string>BootCampHD</string>
|
||||
</array>
|
||||
<key>8BE4DF61-93CA-11D2-AA0D-00E098032B8C</key>
|
||||
<array>
|
||||
|
||||
@ -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;
|
||||
|
||||
/**
|
||||
|
||||
@ -19,6 +19,8 @@
|
||||
|
||||
#include <Guid/FileInfo.h>
|
||||
|
||||
#include <IndustryStandard/Mbr.h>
|
||||
|
||||
#include <Protocol/SimpleFileSystem.h>
|
||||
#include <Protocol/DevicePath.h>
|
||||
#include <Protocol/BlockIo.h>
|
||||
@ -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.
|
||||
|
||||
|
||||
91
Include/Acidanthera/Library/OcLegacyThunkLib.h
Normal file
91
Include/Acidanthera/Library/OcLegacyThunkLib.h
Normal file
@ -0,0 +1,91 @@
|
||||
/** @file
|
||||
This library implements thunking to legacy 16-bit environment.
|
||||
|
||||
Copyright (c) 2023, Goldfish64. All rights reserved.<BR>
|
||||
Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
**/
|
||||
|
||||
#ifndef OC_LEGACY_THUNK_LIB_H
|
||||
#define OC_LEGACY_THUNK_LIB_H
|
||||
|
||||
#include <Protocol/Legacy8259.h>
|
||||
|
||||
//
|
||||
// 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
|
||||
@ -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.
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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:
|
||||
|
||||
@ -47,6 +47,7 @@ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
|
||||
#include <Library/OcLegacyThunkLib.h>
|
||||
#include <Library/OcMemoryLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -1,218 +0,0 @@
|
||||
/** @file
|
||||
Provide legacy thunk interface for accessing Bios Video Rom.
|
||||
|
||||
Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
|
||||
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;
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -26,13 +26,12 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcLegacyThunkLib.h>
|
||||
|
||||
#include <IndustryStandard/Pci.h>
|
||||
|
||||
#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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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
|
||||
|
||||
@ -1,216 +0,0 @@
|
||||
/** @file
|
||||
Provide legacy thunk interface for accessing Bios Block I/O.
|
||||
|
||||
Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
|
||||
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;
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ Abstract:
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/OcLegacyThunkLib.h>
|
||||
#include <Library/PrintLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
|
||||
@ -130,11 +131,4 @@ InitDescriptor (
|
||||
VOID
|
||||
);
|
||||
|
||||
BOOLEAN
|
||||
EFIAPI
|
||||
LegacyBiosInt86 (
|
||||
IN UINT8 BiosInt,
|
||||
IN EFI_IA32_REGISTER_SET *Regs
|
||||
);
|
||||
|
||||
#endif
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
//
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -14,6 +14,8 @@
|
||||
|
||||
#include <Guid/Gpt.h>
|
||||
|
||||
#include <IndustryStandard/Mbr.h>
|
||||
|
||||
#include <Protocol/BlockIo.h>
|
||||
#include <Protocol/BlockIo2.h>
|
||||
#include <Protocol/DiskIo.h>
|
||||
@ -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;
|
||||
}
|
||||
@ -33,7 +33,7 @@
|
||||
LocateFileSystem.c
|
||||
OpenFile.c
|
||||
ReadFile.c
|
||||
GptPartitionEntry.c
|
||||
DiskMisc.c
|
||||
FirmwareFile.c
|
||||
FileMisc.c
|
||||
|
||||
|
||||
477
Library/OcLegacyThunkLib/OcLegacyThunkLib.c
Normal file
477
Library/OcLegacyThunkLib/OcLegacyThunkLib.c
Normal file
@ -0,0 +1,477 @@
|
||||
/** @file
|
||||
This file implements thunking to legacy 16-bit environment.
|
||||
|
||||
Copyright (c) 2023, Goldfish64. All rights reserved.<BR>
|
||||
Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-2-Clause
|
||||
**/
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <IndustryStandard/Pci.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DebugLib.h>
|
||||
#include <Library/IoLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcDeviceMiscLib.h>
|
||||
#include <Library/OcLegacyThunkLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
|
||||
#include <Protocol/PciIo.h>
|
||||
#include <Protocol/Timer.h>
|
||||
|
||||
//
|
||||
// 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;
|
||||
}
|
||||
53
Library/OcLegacyThunkLib/OcLegacyThunkLib.inf
Normal file
53
Library/OcLegacyThunkLib/OcLegacyThunkLib.inf
Normal file
@ -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.<BR>
|
||||
#
|
||||
# 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
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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]);
|
||||
|
||||
275
Platform/OpenLegacyBoot/BiosDisk.c
Normal file
275
Platform/OpenLegacyBoot/BiosDisk.c
Normal file
@ -0,0 +1,275 @@
|
||||
/** @file
|
||||
Copyright (C) 2023, Goldfish64. All rights reserved.<BR>
|
||||
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;
|
||||
}
|
||||
76
Platform/OpenLegacyBoot/LegacyBootInternal.h
Normal file
76
Platform/OpenLegacyBoot/LegacyBootInternal.h
Normal file
@ -0,0 +1,76 @@
|
||||
/** @file
|
||||
Copyright (C) 2023, Goldfish64. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#ifndef LEGACY_BOOT_INTERNAL_H
|
||||
#define LEGACY_BOOT_INTERNAL_H
|
||||
|
||||
#include <Uefi.h>
|
||||
|
||||
#include <IndustryStandard/Mbr.h>
|
||||
|
||||
#include <Library/BaseLib.h>
|
||||
#include <Library/BaseMemoryLib.h>
|
||||
#include <Library/DevicePathLib.h>
|
||||
#include <Library/MemoryAllocationLib.h>
|
||||
#include <Library/OcBootManagementLib.h>
|
||||
#include <Library/OcDebugLogLib.h>
|
||||
#include <Library/OcDevicePathLib.h>
|
||||
#include <Library/OcFileLib.h>
|
||||
#include <Library/OcLegacyThunkLib.h>
|
||||
#include <Library/OcMiscLib.h>
|
||||
#include <Library/UefiBootServicesTableLib.h>
|
||||
#include <Library/UefiLib.h>
|
||||
#include <Library/UefiRuntimeServicesTableLib.h>
|
||||
|
||||
#include <Protocol/DevicePath.h>
|
||||
#include <Protocol/Legacy8259.h>
|
||||
|
||||
/**
|
||||
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
|
||||
502
Platform/OpenLegacyBoot/LegacyBootSupport.c
Normal file
502
Platform/OpenLegacyBoot/LegacyBootSupport.c
Normal file
@ -0,0 +1,502 @@
|
||||
/** @file
|
||||
Copyright (C) 2023, Goldfish64. All rights reserved.<BR>
|
||||
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"<null>",
|
||||
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;
|
||||
}
|
||||
535
Platform/OpenLegacyBoot/OpenLegacyBoot.c
Normal file
535
Platform/OpenLegacyBoot/OpenLegacyBoot.c
Normal file
@ -0,0 +1,535 @@
|
||||
/** @file
|
||||
Legacy boot driver.
|
||||
|
||||
Copyright (c) 2023, Goldfish64. All rights reserved.<BR>
|
||||
SPDX-License-Identifier: BSD-3-Clause
|
||||
**/
|
||||
|
||||
#include "LegacyBootInternal.h"
|
||||
|
||||
#include <Protocol/OcBootEntry.h>
|
||||
|
||||
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;
|
||||
}
|
||||
45
Platform/OpenLegacyBoot/OpenLegacyBoot.inf
Normal file
45
Platform/OpenLegacyBoot/OpenLegacyBoot.inf
Normal file
@ -0,0 +1,45 @@
|
||||
## @file
|
||||
# Legacy boot entry protocol implementation.
|
||||
#
|
||||
# Copyright (C) 2023, Goldfish64. All rights reserved.<BR>
|
||||
# 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
|
||||
@ -198,6 +198,7 @@ package() {
|
||||
"NvmExpressDxe.efi"
|
||||
"OpenCanopy.efi"
|
||||
"OpenHfsPlus.efi"
|
||||
"OpenLegacyBoot.efi"
|
||||
"OpenLinuxBoot.efi"
|
||||
"OpenNtfsDxe.efi"
|
||||
"OpenPartitionDxe.efi"
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user