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