Skip to content

Commit

Permalink
OcBootManagementLib: Add Apple DP expansion for virtio blk
Browse files Browse the repository at this point in the history
Apparently macOS strips down HD nodes from virtio blk devices
leaving them "infix" shortened, i.e. PCI/APFS instead of
PCI/HD/APFS.
  • Loading branch information
vit9696 committed Oct 7, 2024
1 parent 402b3b1 commit 9bab562
Show file tree
Hide file tree
Showing 3 changed files with 175 additions and 3 deletions.
5 changes: 4 additions & 1 deletion Include/Acidanthera/Library/OcDevicePathLib.h
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,8 @@ typedef struct {
restore DevicePathNode's original content in
the case of failure.
On success, data may need to be freed.
@param[in] ValidDevice A device handle pointing to previous valid
device path if any.
@retval -1 DevicePathNode could not be fixed.
@retval 0 DevicePathNode was not modified and may be valid.
Expand All @@ -313,7 +315,8 @@ INTN
OcFixAppleBootDevicePathNode (
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT APPLE_BOOT_DP_PATCH_CONTEXT *RestoreContext OPTIONAL
OUT APPLE_BOOT_DP_PATCH_CONTEXT *RestoreContext OPTIONAL,
IN EFI_HANDLE ValidDevice OPTIONAL
);

/**
Expand Down
1 change: 1 addition & 0 deletions Library/OcBootManagementLib/BootEntryManagement.c
Original file line number Diff line number Diff line change
Expand Up @@ -1459,6 +1459,7 @@ AddBootEntryFromBootOption (
NumPatchedNodes = OcFixAppleBootDevicePathNode (
&DevicePath,
&RemainingDevicePath,
NULL,
NULL
);
} while (NumPatchedNodes > 0);
Expand Down
172 changes: 170 additions & 2 deletions Library/OcDevicePathLib/OcDevicePathLib.c
Original file line number Diff line number Diff line change
Expand Up @@ -408,12 +408,169 @@ InternalExpandNewPath (
return -1;
}

STATIC
INTN
OcFixAppleBootDevicePathNode (
InternalFixAppleBootDevicePathVirtioNode (
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT APPLE_BOOT_DP_PATCH_CONTEXT *RestoreContext OPTIONAL
)
{
EFI_STATUS Status;
UINTN HandleCount;
EFI_HANDLE Device;
EFI_HANDLE *HandleBuffer;
UINTN Index;
UINTN DevicePathSize;
UINTN ValidPrefixSize;
EFI_DEVICE_PATH_PROTOCOL *TestedDevicePath;
EFI_DEVICE_PATH_PROTOCOL *TestedDeviceNode;
EFI_DEVICE_PATH_PROTOCOL *NewDeviceNode;
EFI_DEVICE_PATH_PROTOCOL *FixedDevicePath;
UINTN TestedSize;
UINT8 TestedNodeType;
UINT8 TestedNodeSubType;

//
// Apple may skip HD node for Virtio-BLK devices giving APFS Vendor DP
// right away in their device paths. Try to locate and fix them up.
//

//
// 1. Get all Block Io protocol handles.
//
HandleCount = 0;
Status = gBS->LocateHandleBuffer (
ByProtocol,
&gEfiBlockIoProtocolGuid,
NULL,
&HandleCount,
&HandleBuffer
);

if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_VERBOSE, "Failed to locate any block i/o to fixup DP\n"));
return 0;
}

//
// 2. Calculate prefix size.
//
DevicePathSize = GetDevicePathSize (*DevicePath);
ValidPrefixSize = DevicePathSize - GetDevicePathSize (*DevicePathNode);

for (Index = 0; Index < HandleCount; ++Index) {
//
// 2. Get Device Path protocol from each handle.
//
Status = gBS->HandleProtocol (
HandleBuffer[Index],
&gEfiDevicePathProtocolGuid,
(VOID **)&TestedDevicePath
);

if (EFI_ERROR (Status)) {
continue;
}

//
// 3. Calculate found device path size.
//
TestedSize = GetDevicePathSize (TestedDevicePath);

//
// 4.1 Skip tested device paths that do not match HD paths.
//
if (TestedSize != ValidPrefixSize + sizeof (HARDDRIVE_DEVICE_PATH) + END_DEVICE_PATH_LENGTH) {
continue;
}

//
// 4.2 Skip tested device paths that do not share a common prefix.
//
if (CompareMem (TestedDevicePath, *DevicePath, ValidPrefixSize) != 0) {
continue;
}

//
// 4.3 Skip tested device paths that are not adding HD nodes.
//
TestedDeviceNode = (VOID *)((UINTN)TestedDevicePath + ValidPrefixSize);
TestedNodeType = DevicePathType (TestedDeviceNode);
TestedNodeSubType = DevicePathSubType (TestedDeviceNode);
if ( (TestedNodeType != MEDIA_DEVICE_PATH)
|| (TestedNodeSubType != MEDIA_HARDDRIVE_DP))
{
continue;
}

//
// 5. Initial checks matched. Build fixed device path.
//
FixedDevicePath = AllocatePool (DevicePathSize + sizeof (HARDDRIVE_DEVICE_PATH));
if (FixedDevicePath == NULL) {
FreePool (HandleBuffer);
return 0;
}

CopyMem (
FixedDevicePath,
TestedDevicePath,
ValidPrefixSize + sizeof (HARDDRIVE_DEVICE_PATH)
);

TestedDeviceNode = (VOID *)((UINTN)FixedDevicePath + ValidPrefixSize + sizeof (HARDDRIVE_DEVICE_PATH));

CopyMem (
*DevicePathNode,
(VOID *)((UINTN)*DevicePath + ValidPrefixSize),
DevicePathSize - ValidPrefixSize
);

//
// 6. Check this is the right partition.
//
NewDeviceNode = FixedDevicePath;
Status = gBS->LocateDevicePath (
&gEfiDevicePathProtocolGuid,
&NewDeviceNode,
&Device
);
if (EFI_ERROR (Status)) {
FreePool (FixedDevicePath);
continue;
}

//
// If the discovered device path is past the HD path, then it is ours.
// Otherwise we picked up wrong partition and need to retry.
//
if ((UINTN)NewDeviceNode > (UINTN)TestedDeviceNode) {
RestoreContext->OldPath = *DevicePath;
*DevicePath = FixedDevicePath;
*DevicePathNode = TestedDeviceNode;
FreePool (HandleBuffer);
return 1;
}

FreePool (FixedDevicePath);
}

FreePool (HandleBuffer);

//
// We found nothing.
//
return 0;
}

INTN
OcFixAppleBootDevicePathNode (
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePathNode,
OUT APPLE_BOOT_DP_PATCH_CONTEXT *RestoreContext OPTIONAL,
IN EFI_HANDLE ValidDevice OPTIONAL
)
{
INTN Result;
EFI_DEVICE_PATH_PROTOCOL *OldPath;
Expand Down Expand Up @@ -624,6 +781,16 @@ OcFixAppleBootDevicePathNode (
default:
break;
}
} else if ((NodeType == MEDIA_DEVICE_PATH) && (NodeSubType == MEDIA_VENDOR_DP)) {
if (ValidDevice == NULL) {
return 0;
}

return InternalFixAppleBootDevicePathVirtioNode (
DevicePath,
DevicePathNode,
RestoreContext
);
}

return 0;
Expand Down Expand Up @@ -669,7 +836,8 @@ OcFixAppleBootDevicePath (
Result = OcFixAppleBootDevicePathNode (
DevicePath,
RemainingDevicePath,
RestoreContextPtr
RestoreContextPtr,
Device
);
//
// Save a restore context only for the first processing of the first node.
Expand Down

0 comments on commit 9bab562

Please sign in to comment.