mirror of
https://github.com/acidanthera/OpenCorePkg.git
synced 2025-12-08 19:25:01 +00:00
267 lines
7.4 KiB
C
267 lines
7.4 KiB
C
/** @file
|
|
Decode a hard disk partitioned with the APM scheme.
|
|
|
|
Copyright (c) 2016-2021, Acidanthera. All rights reserved.<BR>
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include "Partition.h"
|
|
|
|
/**
|
|
Install child handles if the Handle supports Apple format.
|
|
|
|
@param[in] This Calling context.
|
|
@param[in] Handle Parent Handle.
|
|
@param[in] DiskIo Parent DiskIo interface.
|
|
@param[in] DiskIo2 Parent DiskIo2 interface.
|
|
@param[in] BlockIo Parent BlockIo interface.
|
|
@param[in] BlockIo2 Parent BlockIo2 interface.
|
|
@param[in] DevicePath Parent Device Path
|
|
|
|
|
|
@retval EFI_SUCCESS Child handle(s) was added.
|
|
@retval EFI_MEDIA_CHANGED Media changed Detected.
|
|
@retval other no child handle was added.
|
|
|
|
**/
|
|
EFI_STATUS
|
|
PartitionInstallAppleChildHandles (
|
|
IN EFI_DRIVER_BINDING_PROTOCOL *This,
|
|
IN EFI_HANDLE Handle,
|
|
IN EFI_DISK_IO_PROTOCOL *DiskIo,
|
|
IN EFI_DISK_IO2_PROTOCOL *DiskIo2,
|
|
IN EFI_BLOCK_IO_PROTOCOL *BlockIo,
|
|
IN EFI_BLOCK_IO2_PROTOCOL *BlockIo2,
|
|
IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
|
|
)
|
|
{
|
|
EFI_STATUS Status;
|
|
UINT32 BlockSize;
|
|
APM_DRIVER_DESCRIPTOR_MAP *Apm;
|
|
APM_ENTRY *ApmEntry;
|
|
UINTN NumberOfPartitionEntries;
|
|
UINT64 Offset;
|
|
UINT64 PartitionSize;
|
|
UINT64 PartitionStart;
|
|
EFI_LBA StartingLBA;
|
|
EFI_LBA EndingLBA;
|
|
UINT64 LBASize;
|
|
UINT32 Remainder;
|
|
UINTN Index;
|
|
EFI_STATUS ApmStatus;
|
|
HARDDRIVE_DEVICE_PATH HdDev;
|
|
EFI_PARTITION_INFO_PROTOCOL PartitionInfo;
|
|
APPLE_PARTITION_INFO_PROTOCOL ApplePartitionInfo;
|
|
|
|
//
|
|
// Check whether a medium is present
|
|
//
|
|
if (BlockIo->Media == NULL) {
|
|
return EFI_NO_MEDIA;
|
|
}
|
|
|
|
//
|
|
// Cerify the partition is physical
|
|
//
|
|
if (BlockIo->Media->LogicalPartition) {
|
|
return EFI_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// Allocate a buffer for the APM Driver Descriptor Map
|
|
//
|
|
Apm = AllocatePool (BlockIo->Media->BlockSize);
|
|
if (Apm == NULL) {
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
ApmStatus = EFI_NOT_FOUND;
|
|
|
|
//
|
|
// Read the APM Driver Descriptor Map from LBA #0
|
|
//
|
|
Status = BlockIo->ReadBlocks (
|
|
BlockIo,
|
|
BlockIo->Media->MediaId,
|
|
0,
|
|
BlockIo->Media->BlockSize,
|
|
Apm
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
gBS->FreePool (Apm);
|
|
return Status;
|
|
}
|
|
|
|
//
|
|
// Verify that the APM Driver Descriptor Map is valid
|
|
//
|
|
if (Apm->Signature != APM_DRIVER_DESCRIPTOR_MAP_SIGNATURE) {
|
|
gBS->FreePool (Apm);
|
|
return EFI_NOT_FOUND;
|
|
}
|
|
|
|
BlockSize = SwapBytes16 (Apm->BlockSize);
|
|
|
|
//
|
|
// Allocate a buffer for an APM Entry
|
|
//
|
|
ApmEntry = AllocatePool (BlockSize);
|
|
|
|
if (ApmEntry == NULL) {
|
|
FreePool (Apm);
|
|
return EFI_OUT_OF_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// Read the APM from LBA #1
|
|
//
|
|
Status = DiskIo->ReadDisk (
|
|
DiskIo,
|
|
BlockIo->Media->MediaId,
|
|
BlockSize,
|
|
BlockSize,
|
|
ApmEntry
|
|
);
|
|
if (EFI_ERROR (Status)) {
|
|
ApmStatus = Status;
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Verify that the APM is valid
|
|
//
|
|
if ( (ApmEntry->Signature != APM_ENTRY_SIGNATURE)
|
|
|| (CompareMem (ApmEntry->PartitionType, APM_ENTRY_TYPE_APM, sizeof (APM_ENTRY_TYPE_APM)) != 0))
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
NumberOfPartitionEntries = SwapBytes32 (ApmEntry->NumberOfPartitionEntries);
|
|
|
|
//
|
|
// Check if there are Apple Partition Entries
|
|
//
|
|
if (NumberOfPartitionEntries < 2) {
|
|
goto Done;
|
|
}
|
|
|
|
Offset = 2 * BlockSize;
|
|
|
|
//
|
|
// Read the Apple Partition Entries
|
|
//
|
|
for (Index = 1; Index < NumberOfPartitionEntries; ++Index, Offset += BlockSize) {
|
|
Status = DiskIo->ReadDisk (
|
|
DiskIo,
|
|
BlockIo->Media->MediaId,
|
|
Offset,
|
|
BlockSize,
|
|
ApmEntry
|
|
);
|
|
|
|
if ( EFI_ERROR (Status)
|
|
|| (ApmEntry->Signature != APM_ENTRY_SIGNATURE))
|
|
{
|
|
goto Done;
|
|
}
|
|
|
|
//
|
|
// Verify that the Apple Partition Entry is valid
|
|
//
|
|
if ( (CompareMem (ApmEntry->PartitionType, APM_ENTRY_TYPE_FREE, sizeof (APM_ENTRY_TYPE_FREE)) == 0)
|
|
|| (SwapBytes32 (ApmEntry->PartitionSize) == 0))
|
|
{
|
|
continue;
|
|
}
|
|
|
|
PartitionStart = SwapBytes32 (ApmEntry->PartitionStart);
|
|
|
|
StartingLBA = DivU64x32Remainder (
|
|
MultU64x32 (PartitionStart, BlockSize),
|
|
BlockIo->Media->BlockSize,
|
|
&Remainder
|
|
);
|
|
|
|
if (Remainder != 0) {
|
|
continue;
|
|
}
|
|
|
|
// BUG: Already calculated above -> cache!
|
|
PartitionSize = SwapBytes32 (ApmEntry->PartitionSize);
|
|
|
|
LBASize = DivU64x32Remainder (
|
|
MultU64x32 (PartitionSize, BlockSize),
|
|
BlockIo->Media->BlockSize,
|
|
&Remainder
|
|
);
|
|
|
|
if (Remainder != 0) {
|
|
continue;
|
|
}
|
|
|
|
EndingLBA = StartingLBA + LBASize - 1;
|
|
|
|
if (EndingLBA > BlockIo->Media->LastBlock) {
|
|
continue;
|
|
}
|
|
|
|
ZeroMem (&HdDev, sizeof (HdDev));
|
|
HdDev.Header.Type = MEDIA_DEVICE_PATH;
|
|
HdDev.Header.SubType = MEDIA_HARDDRIVE_DP;
|
|
SetDevicePathNodeLength (&HdDev.Header, sizeof (HdDev));
|
|
|
|
HdDev.PartitionNumber = (UINT32)Index + 1;
|
|
HdDev.MBRType = MBR_TYPE_APPLE_PARTITION_TABLE_HEADER;
|
|
HdDev.PartitionStart = StartingLBA;
|
|
HdDev.PartitionSize = LBASize;
|
|
|
|
DEBUG ((EFI_D_INFO, " Index : %d\n", Index));
|
|
DEBUG ((EFI_D_INFO, " Start LBA : %x\n", HdDev.PartitionStart));
|
|
DEBUG ((EFI_D_INFO, " End LBA: %x\n", EndingLBA));
|
|
DEBUG ((EFI_D_INFO, " Partition size: %x\n", HdDev.PartitionSize));
|
|
DEBUG ((EFI_D_INFO, " Start : %x", MultU64x32 (PartitionStart, BlockSize)));
|
|
DEBUG ((EFI_D_INFO, " End : %x", MultU64x32 ((PartitionStart + PartitionSize - 1), BlockSize)));
|
|
|
|
ZeroMem (&PartitionInfo, sizeof (EFI_PARTITION_INFO_PROTOCOL));
|
|
PartitionInfo.Revision = EFI_PARTITION_INFO_PROTOCOL_REVISION;
|
|
PartitionInfo.Type = PARTITION_TYPE_OTHER;
|
|
|
|
ZeroMem (&ApplePartitionInfo, sizeof (APPLE_PARTITION_INFO_PROTOCOL));
|
|
ApplePartitionInfo.Revision = APPLE_PARTITION_INFO_REVISION;
|
|
ApplePartitionInfo.PartitionNumber = HdDev.PartitionNumber;
|
|
ApplePartitionInfo.MBRType = HdDev.MBRType;
|
|
ApplePartitionInfo.PartitionStart = HdDev.PartitionStart;
|
|
ApplePartitionInfo.PartitionSize = HdDev.PartitionSize;
|
|
|
|
CopyMem (&ApplePartitionInfo.PartitionType, ApmEntry->PartitionType, sizeof (EFI_GUID));
|
|
|
|
Status = PartitionInstallChildHandle (
|
|
This,
|
|
Handle,
|
|
DiskIo,
|
|
DiskIo2,
|
|
BlockIo,
|
|
BlockIo2,
|
|
DevicePath,
|
|
(EFI_DEVICE_PATH_PROTOCOL *)&HdDev,
|
|
&PartitionInfo,
|
|
&ApplePartitionInfo,
|
|
StartingLBA,
|
|
EndingLBA,
|
|
BlockIo->Media->BlockSize,
|
|
(EFI_GUID *)&ApplePartitionInfo.PartitionType
|
|
);
|
|
|
|
if (!EFI_ERROR (Status)) {
|
|
ApmStatus = EFI_SUCCESS;
|
|
}
|
|
}
|
|
|
|
Done:
|
|
FreePool (ApmEntry);
|
|
FreePool (Apm);
|
|
|
|
return ApmStatus;
|
|
}
|