Skip to content

Commit

Permalink
OpenLegacyBoot: Implement active partition switching
Browse files Browse the repository at this point in the history
  • Loading branch information
Goldfish64 committed Aug 17, 2023
1 parent 387adeb commit e03a577
Show file tree
Hide file tree
Showing 5 changed files with 310 additions and 49 deletions.
63 changes: 59 additions & 4 deletions Include/Acidanthera/Library/OcFileLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,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.
**/
Expand Down Expand Up @@ -630,17 +648,54 @@ OcGetGptPartitionEntry (
/**
Retrieve the disk MBR table, if applicable.
@param[in] DiskHandle Disk device handle to retrive MBR partition table from.
@param[in] UseBlockIo2 Use 2nd revision of Block I/O if available.
@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 partition entry list or NULL.
@retval MBR partition table or NULL.
**/
MASTER_BOOT_RECORD *
OcGetDiskMbrTable (
IN EFI_HANDLE DiskHandle,
IN BOOLEAN UseBlockIo2
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,
Expand Down
226 changes: 209 additions & 17 deletions Library/OcFileLib/DiskMisc.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,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,
Expand All @@ -49,6 +51,9 @@ OcDiskInitializeContext (
{
EFI_STATUS Status;

ASSERT (Context != NULL);
ASSERT (DiskHandle != NULL);

//
// Retrieve the Block I/O protocol.
//
Expand Down Expand Up @@ -142,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 (
Expand Down Expand Up @@ -723,7 +763,7 @@ OcGetGptPartitionEntry (
MASTER_BOOT_RECORD *
OcGetDiskMbrTable (
IN EFI_HANDLE DiskHandle,
IN BOOLEAN UseBlockIo2
IN BOOLEAN CheckPartitions
)
{
EFI_STATUS Status;
Expand All @@ -741,7 +781,7 @@ OcGetDiskMbrTable (
Status = OcDiskInitializeContext (
&DiskContext,
DiskHandle,
UseBlockIo2
TRUE
);
if (EFI_ERROR (Status)) {
return NULL;
Expand Down Expand Up @@ -775,27 +815,178 @@ OcGetDiskMbrTable (
return NULL;
}

if ( (Mbr->Partition[0].OSIndicator == PMBR_GPT_PARTITION)
&& (*((UINT32 *)Mbr->Partition[0].StartingLBA) == 0x01)
&& (*((UINT32 *)Mbr->Partition[0].SizeInLBA) != 0))
{
IsProtectiveMbr = TRUE;
for (Index = 1; Index < MAX_MBR_PARTITIONS; Index++) {
if ((*((UINT32 *)Mbr->Partition[Index].StartingLBA) != 0) || (*((UINT32 *)Mbr->Partition[Index].SizeInLBA) != 0)) {
IsProtectiveMbr = FALSE;
break;
if (CheckPartitions) {
if ( (Mbr->Partition[0].OSIndicator == PMBR_GPT_PARTITION)
&& (*((UINT32 *)Mbr->Partition[0].StartingLBA) == 0x01)
&& (*((UINT32 *)Mbr->Partition[0].SizeInLBA) != 0))
{
IsProtectiveMbr = TRUE;
for (Index = 1; Index < MAX_MBR_PARTITIONS; Index++) {
if ((*((UINT32 *)Mbr->Partition[Index].StartingLBA) != 0) || (*((UINT32 *)Mbr->Partition[Index].SizeInLBA) != 0)) {
IsProtectiveMbr = FALSE;
break;
}
}
}

if (IsProtectiveMbr) {
FreePool (Mbr);
return NULL;
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 ( (*((UINT32 *)Mbr->Partition[Index].StartingLBA) == HdNode->PartitionStart)
&& (*((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,
Expand Down Expand Up @@ -858,7 +1049,7 @@ OcDiskFindActiveMbrPartitionPath (

Mbr = OcGetDiskMbrTable (
DiskHandle,
HasBlockIo2
TRUE
);
if (Mbr == NULL) {
return NULL;
Expand All @@ -870,8 +1061,9 @@ OcDiskFindActiveMbrPartitionPath (
//
ActivePartition = -1;
for (Index = 0; Index < MAX_MBR_PARTITIONS; Index++) {
if (Mbr->Partition[Index].BootIndicator == 0x80) {
if (Mbr->Partition[Index].BootIndicator == MBR_PARTITION_ACTIVE) {
ActivePartition = (INT32)Index;
break;
}
}

Expand Down
3 changes: 1 addition & 2 deletions Platform/OpenLegacyBoot/LegacyBootInternal.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,7 @@ InternalGetPartitionLegacyOsType (

EFI_STATUS
InternalLoadLegacyPbr (
IN EFI_DEVICE_PATH_PROTOCOL *PartitionPath,
IN EFI_HANDLE PartitionHandle
IN EFI_DEVICE_PATH_PROTOCOL *PartitionPath
);

#endif // LEGACY_BOOT_INTERNAL_H
Loading

0 comments on commit e03a577

Please sign in to comment.