CherryDev86
CherryDev86

Reputation: 11

How do I get a Unique Partition GUID from a device path in gnu-efi?

How do I get a Unique Partition GUID from a device path in GNU-EFI? I have acquired the Device Path and also have been able to convert it to a text form.

I have tried to Get the Device Path from the BLOCK I/O Protocol, print out the amount of Block I/O handles and convert it to a device path and then convert it to text and print it out.

#include <efi.h>
#include <efilib.h>

// Function to print a device path node
VOID PrintDevicePathNode(EFI_DEVICE_PATH_PROTOCOL* Node) {
    CHAR16* Text = NULL;

    Text = DevicePathToStr(Node);
    if (Text != NULL) {
        Print(L"%s", Text);
        FreePool(Text);
    }
}

// Function to print the entire device path
VOID PrintDevicePath(EFI_DEVICE_PATH_PROTOCOL* DevicePath) {
    while (!IsDevicePathEnd(DevicePath)) {
        PrintDevicePathNode(DevicePath);
        DevicePath = NextDevicePathNode(DevicePath);
        if (!IsDevicePathEnd(DevicePath)) {
            Print(L"\\");
        }
    }
    Print(L"\n");
}

EFI_STATUS efi_main(EFI_HANDLE ImageHandle, EFI_SYSTEM_TABLE* SystemTable) {
    InitializeLib(ImageHandle, SystemTable);

    EFI_STATUS Status;
    EFI_INPUT_KEY Key;

    EFI_BOOT_SERVICES* BS = SystemTable->BootServices;

    EFI_HANDLE* handles;
    UINTN HandleCount;

    Status = uefi_call_wrapper(BS->LocateHandleBuffer, 5, ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &HandleCount, &handles);
    if (EFI_ERROR(Status)) {
        Print(L"Error locating handles with Block I/O Protocol: %r\n", Status);
        return Status;
    }

    Print(L"Number of handles with Block I/O Protocol: %d\n", HandleCount);

    for (UINTN i = 0; i < HandleCount; i++) {
        EFI_BLOCK_IO_PROTOCOL* blockIo;
        Status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], &gEfiBlockIoProtocolGuid, (VOID**)&blockIo);
        if (EFI_ERROR(Status)) {
            Print(L"Error getting Block I/O Protocol from handle %d: %r\n", i, Status);
            continue;
        }

        EFI_BLOCK_IO_MEDIA* media = blockIo->Media;

        Print(L"Block Device %d\n", i);
        Print(L"  Media ID: %lx\n", media->MediaId);
        Print(L"  Block Size: %d\n", media->BlockSize);
        Print(L"  Device Size: %ld MB\n", (media->LastBlock + 1) * media->BlockSize / (1024 * 1024));

        EFI_DEVICE_PATH_PROTOCOL* devicePath;
        Status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i], &gEfiDevicePathProtocolGuid, (VOID**)&devicePath);
        if (!EFI_ERROR(Status)) {
            Print(L"  Device Path:\n");
            PrintDevicePath(devicePath);
        }
    }

    Status = ST->ConIn->Reset(ST->ConIn, FALSE);
    if (EFI_ERROR(Status))
        return Status;

    while ((Status = ST->ConIn->ReadKeyStroke(ST->ConIn, &Key)) == EFI_NOT_READY);

    return Status;
}

Upvotes: 1

Views: 154

Answers (1)

MiSimon
MiSimon

Reputation: 1538

You can search for a HARDDRIVE_DEVICE_PATH node with SignatureType == 0x02. The partition/disk signature is stored in this struct.

EFI_STATUS GetFirstGptSignature(CONST EFI_DEVICE_PATH_PROTOCOL* DevicePath, EFI_GUID* GptSignature) {
    CONST HARDDRIVE_DEVICE_PATH* DevicePathMask;

    if(!DevicePath || !GptSignature) {
        return EFI_INVALID_PARAMETER;
    }

    while (!IsDevicePathEnd(DevicePath)) {
        DevicePathMask = (CONST HARDDRIVE_DEVICE_PATH*)DevicePath;
        DevicePath = NextDevicePathNode(DevicePath);

        if(DevicePathMask->Header.Type != MEDIA_DEVICE_PATH) {
            continue;
        }
        if(DevicePathMask->Header.SubType != MEDIA_HARDDRIVE_DP) {
            continue;
        }

        // Check if the device path describes a GPT partition or disk
        if(DevicePathMask->SignatureType != 2) {
            continue;
        }
    
        CopyMem(GptSignature, DevicePathMask->Signature, sizeof(EFI_GUID));
        return EFI_SUCCESS;       
    }

    return EFI_NOT_FOUND;
}

Upvotes: 1

Related Questions