Implement legacy OS booting support (#482)

This commit is contained in:
John Davis 2023-09-07 20:00:30 -05:00 committed by GitHub
parent 2bbda9de78
commit bb44e89add
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
38 changed files with 3130 additions and 987 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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;
/**

View File

@ -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.

View 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

View File

@ -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.

View File

@ -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

View File

@ -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:

View File

@ -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

View File

@ -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]

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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

View File

@ -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
//

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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;

View File

@ -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;
}

View File

@ -33,7 +33,7 @@
LocateFileSystem.c
OpenFile.c
ReadFile.c
GptPartitionEntry.c
DiskMisc.c
FirmwareFile.c
FileMisc.c

View 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;
}

View 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

View File

@ -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

View File

@ -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

View File

@ -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]

View File

@ -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]);

View 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;
}

View 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

View 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;
}

View 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;
}

View 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

View File

@ -198,6 +198,7 @@ package() {
"NvmExpressDxe.efi"
"OpenCanopy.efi"
"OpenHfsPlus.efi"
"OpenLegacyBoot.efi"
"OpenLinuxBoot.efi"
"OpenNtfsDxe.efi"
"OpenPartitionDxe.efi"