[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH] x86-64/EFI: construct EDD data from device path protocol information



In the absence of a BIOS to handle INT13 requests, this information
must be constructed artificially instead when booted from EFI.

Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>

--- a/xen/arch/x86/boot/edd.S
+++ b/xen/arch/x86/boot/edd.S
@@ -16,21 +16,13 @@
  * Updated and ported for Xen by Keir Fraser <keir@xxxxxxxxxxxxx> June 2007
  */
 
+#include <asm/edd.h>
+
         .code16
 
 /* Offset of disc signature in the MBR. */
 #define EDD_MBR_SIG_OFFSET      0x1B8
 
-/* Maximum number of EDD information structures at boot_edd_info. */
-#define EDD_INFO_MAX            6
-
-/* Maximum number of MBR signatures at boot_mbr_signature. */
-#define EDD_MBR_SIG_MAX         16
-
-/* Size of components of EDD information structure. */
-#define EDDEXTSIZE              8
-#define EDDPARMSIZE             74
-
 get_edd:
         cmpb    $2, bootsym(opt_edd)            # edd=off ?
         je      edd_done
--- a/xen/arch/x86/efi/boot.c
+++ b/xen/arch/x86/efi/boot.c
@@ -16,6 +16,7 @@
 #include <xen/stringify.h>
 #include <xen/vga.h>
 #include <asm/e820.h>
+#include <asm/edd.h>
 #include <asm/mm.h>
 #include <asm/msr.h>
 #include <asm/processor.h>
@@ -539,6 +540,18 @@ static void __init split_value(char *s)
     *s = 0;
 }
 
+static void __init edd_put_string(u8 *dst, size_t n, const char *src)
+{
+    while ( n-- && *src )
+       *dst++ = *src++;
+    if ( *src )
+       PrintErrMesg(L"Internal error populating EDD info",
+                    EFI_BUFFER_TOO_SMALL);
+    while ( n-- )
+       *dst++ = ' ';
+}
+#define edd_put_string(d, s) edd_put_string(d, ARRAY_SIZE(d), s)
+
 static int __init set_color(u32 mask, int bpp, u8 *pos, u8 *sz)
 {
    if ( bpp < 0 )
@@ -604,6 +617,8 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY
 {
     static EFI_GUID __initdata loaded_image_guid = LOADED_IMAGE_PROTOCOL;
     static EFI_GUID __initdata gop_guid = EFI_GRAPHICS_OUTPUT_PROTOCOL_GUID;
+    static EFI_GUID __initdata bio_guid = BLOCK_IO_PROTOCOL;
+    static EFI_GUID __initdata devp_guid = DEVICE_PATH_PROTOCOL;
     EFI_LOADED_IMAGE *loaded_image;
     EFI_STATUS status;
     unsigned int i, argc;
@@ -883,7 +898,148 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY
 
     place_string(&mbi.mem_upper, NULL);
 
-    /* XXX Collect EDD info. */
+    /* Collect EDD info. */
+    BUILD_BUG_ON(offsetof(struct edd_info, edd_device_params) != EDDEXTSIZE);
+    BUILD_BUG_ON(sizeof(struct edd_device_params) != EDDPARMSIZE);
+    size = 0;
+    status = efi_bs->LocateHandle(ByProtocol, &bio_guid, NULL, &size, NULL);
+    if ( status == EFI_BUFFER_TOO_SMALL )
+        status = efi_bs->AllocatePool(EfiLoaderData, size, (void **)&handles);
+    if ( !EFI_ERROR(status) )
+        status = efi_bs->LocateHandle(ByProtocol, &bio_guid, NULL, &size,
+                                      handles);
+    if ( EFI_ERROR(status) )
+        size = 0;
+    for ( i = 0; i < size / sizeof(*handles); ++i )
+    {
+        EFI_BLOCK_IO *bio;
+        EFI_DEV_PATH_PTR devp;
+        struct edd_info *info = boot_edd_info + boot_edd_info_nr;
+        struct edd_device_params *params = &info->edd_device_params;
+        enum { root, acpi, pci, ctrlr } state = root;
+
+        status = efi_bs->HandleProtocol(handles[i], &bio_guid, (void **)&bio);
+        if ( EFI_ERROR(status) ||
+             bio->Media->RemovableMedia ||
+             bio->Media->LogicalPartition )
+            continue;
+        if ( boot_edd_info_nr < EDD_INFO_MAX )
+        {
+            info->device = 0x80 + boot_edd_info_nr; /* fake */
+            info->version = 0x11;
+            params->length = offsetof(struct edd_device_params, dpte_ptr);
+            params->number_of_sectors = bio->Media->LastBlock + 1;
+            params->bytes_per_sector = bio->Media->BlockSize;
+            params->dpte_ptr = ~0;
+        }
+        ++boot_edd_info_nr;
+        status = efi_bs->HandleProtocol(handles[i], &devp_guid,
+                                        (void **)&devp);
+        if ( EFI_ERROR(status) )
+            continue;
+        for ( ; !IsDevicePathEnd(devp.DevPath);
+              devp.DevPath = NextDevicePathNode(devp.DevPath) )
+        {
+            switch ( DevicePathType(devp.DevPath) )
+            {
+                const u8 *p;
+
+            case ACPI_DEVICE_PATH:
+                if ( state != root || boot_edd_info_nr > EDD_INFO_MAX )
+                    break;
+                switch ( DevicePathSubType(devp.DevPath) )
+                {
+                case ACPI_DP:
+                    if ( devp.Acpi->HID != EISA_PNP_ID(0xA03) &&
+                         devp.Acpi->HID != EISA_PNP_ID(0xA08) )
+                        break;
+                    params->interface_path.pci.bus = devp.Acpi->UID;
+                    state = acpi;
+                    break;
+                case EXPANDED_ACPI_DP:
+                    /* XXX */
+                    break;
+                }
+                break;
+            case HARDWARE_DEVICE_PATH:
+                if ( state != acpi ||
+                     DevicePathSubType(devp.DevPath) != HW_PCI_DP ||
+                     boot_edd_info_nr > EDD_INFO_MAX )
+                    break;
+                state = pci;
+                edd_put_string(params->host_bus_type, "PCI");
+                params->interface_path.pci.slot = devp.Pci->Device;
+                params->interface_path.pci.function = devp.Pci->Function;
+                break;
+            case MESSAGING_DEVICE_PATH:
+                if ( state != pci || boot_edd_info_nr > EDD_INFO_MAX )
+                    break;
+                state = ctrlr;
+                switch ( DevicePathSubType(devp.DevPath) )
+                {
+                case MSG_ATAPI_DP:
+                    edd_put_string(params->interface_type, "ATAPI");
+                    params->interface_path.pci.channel =
+                        devp.Atapi->PrimarySecondary;
+                    params->device_path.atapi.device = devp.Atapi->SlaveMaster;
+                    params->device_path.atapi.lun = devp.Atapi->Lun;
+                    break;
+                case MSG_SCSI_DP:
+                    edd_put_string(params->interface_type, "SCSI");
+                    params->device_path.scsi.id = devp.Scsi->Pun;
+                    params->device_path.scsi.lun = devp.Scsi->Lun;
+                    break;
+                case MSG_FIBRECHANNEL_DP:
+                    edd_put_string(params->interface_type, "FIBRE");
+                    params->device_path.fibre.wwid = devp.FibreChannel->WWN;
+                    params->device_path.fibre.lun = devp.FibreChannel->Lun;
+                    break;
+                case MSG_1394_DP:
+                    edd_put_string(params->interface_type, "1394");
+                    params->device_path.i1394.eui = devp.F1394->Guid;
+                    break;
+                case MSG_USB_DP:
+                case MSG_USB_CLASS_DP:
+                    edd_put_string(params->interface_type, "USB");
+                    break;
+                case MSG_I2O_DP:
+                    edd_put_string(params->interface_type, "I2O");
+                    params->device_path.i2o.identity_tag = devp.I2O->Tid;
+                    break;
+                default:
+                    continue;
+                }
+                info->version = 0x30;
+                params->length = sizeof(struct edd_device_params);
+                params->key = 0xbedd;
+                params->device_path_info_length =
+                    sizeof(struct edd_device_params) -
+                    offsetof(struct edd_device_params, key);
+                for ( p = (const u8 *)&params->key; p < &params->checksum; ++p 
)
+                    params->checksum -= *p;
+                break;
+            case MEDIA_DEVICE_PATH:
+                if ( DevicePathSubType(devp.DevPath) == MEDIA_HARDDRIVE_DP &&
+                     devp.HardDrive->MBRType == MBR_TYPE_PCAT &&
+                     boot_mbr_signature_nr < EDD_MBR_SIG_MAX )
+                {
+                    struct mbr_signature *sig = boot_mbr_signature +
+                                                boot_mbr_signature_nr;
+
+                    sig->device = 0x80 + boot_edd_info_nr; /* fake */
+                    memcpy(&sig->signature, devp.HardDrive->Signature,
+                           sizeof(sig->signature));
+                    ++boot_mbr_signature_nr;
+                }
+                break;
+            }
+        }
+    }
+    if ( handles )
+        efi_bs->FreePool(handles);
+    if ( boot_edd_info_nr > EDD_INFO_MAX )
+        boot_edd_info_nr = EDD_INFO_MAX;
+
     /* XXX Collect EDID info. */
 
     if ( cpuid_eax(0x80000000) > 0x80000000 )
--- a/xen/include/asm-x86/edd.h
+++ b/xen/include/asm-x86/edd.h
@@ -23,6 +23,8 @@
 #ifndef __XEN_EDD_H__
 #define __XEN_EDD_H__
 
+#ifndef __ASSEMBLY__
+
 struct edd_info {
     /* Int13, Fn48: Check Extensions Present. */
     u8 device;                   /* %dl: device */
@@ -33,10 +35,106 @@ struct edd_info {
     u8 legacy_max_head;          /* %dh: maximum head number */
     u8 legacy_sectors_per_track; /* %cl[5:0]: maximum sector number */
     /* Int13, Fn41: Get Device Parameters (as filled into %ds:%esi). */
-    struct {
+    struct edd_device_params {
         u16 length;
-        u8 data[72];
-    } edd_device_params;
+        u16 info_flags;
+        u32 num_default_cylinders;
+        u32 num_default_heads;
+        u32 sectors_per_track;
+        u64 number_of_sectors;
+        u16 bytes_per_sector;
+        u32 dpte_ptr;            /* 0xFFFFFFFF for our purposes */
+        u16 key;                 /* = 0xBEDD */
+        u8 device_path_info_length;
+        u8 reserved2;
+        u16 reserved3;
+        u8 host_bus_type[4];
+        u8 interface_type[8];
+        union {
+            struct {
+                u16 base_address;
+                u16 reserved1;
+                u32 reserved2;
+            } __attribute__ ((packed)) isa;
+            struct {
+                u8 bus;
+                u8 slot;
+                u8 function;
+                u8 channel;
+                u32 reserved;
+            } __attribute__ ((packed)) pci;
+            /* pcix is same as pci */
+            struct {
+                u64 reserved;
+            } __attribute__ ((packed)) ibnd;
+            struct {
+                u64 reserved;
+            } __attribute__ ((packed)) xprs;
+            struct {
+                u64 reserved;
+            } __attribute__ ((packed)) htpt;
+            struct {
+                u64 reserved;
+            } __attribute__ ((packed)) unknown;
+        } interface_path;
+        union {
+            struct {
+                u8 device;
+                u8 reserved1;
+                u16 reserved2;
+                u32 reserved3;
+                u64 reserved4;
+            } __attribute__ ((packed)) ata;
+            struct {
+                u8 device;
+                u8 lun;
+                u8 reserved1;
+                u8 reserved2;
+                u32 reserved3;
+                u64 reserved4;
+            } __attribute__ ((packed)) atapi;
+            struct {
+                u16 id;
+                u64 lun;
+                u16 reserved1;
+                u32 reserved2;
+            } __attribute__ ((packed)) scsi;
+            struct {
+                u64 serial_number;
+                u64 reserved;
+            } __attribute__ ((packed)) usb;
+            struct {
+                u64 eui;
+                u64 reserved;
+            } __attribute__ ((packed)) i1394;
+            struct {
+                u64 wwid;
+                u64 lun;
+            } __attribute__ ((packed)) fibre;
+            struct {
+                u64 identity_tag;
+                u64 reserved;
+            } __attribute__ ((packed)) i2o;
+            struct {
+                u32 array_number;
+                u32 reserved1;
+                u64 reserved2;
+            } __attribute__ ((packed)) raid;
+            struct {
+                u8 device;
+                u8 reserved1;
+                u16 reserved2;
+                u32 reserved3;
+                u64 reserved4;
+            } __attribute__ ((packed)) sata;
+            struct {
+                u64 reserved1;
+                u64 reserved2;
+            } __attribute__ ((packed)) unknown;
+        } device_path;
+        u8 reserved4;
+        u8 checksum;
+    } __attribute__ ((packed)) edd_device_params;
 } __attribute__ ((packed));
 
 struct mbr_signature {
@@ -51,4 +149,16 @@ extern u8 boot_mbr_signature_nr;
 extern struct edd_info boot_edd_info[];
 extern u8 boot_edd_info_nr;
 
+#endif /* __ASSEMBLY__ */
+
+/* Maximum number of EDD information structures at boot_edd_info. */
+#define EDD_INFO_MAX            6
+
+/* Maximum number of MBR signatures at boot_mbr_signature. */
+#define EDD_MBR_SIG_MAX         16
+
+/* Size of components of EDD information structure. */
+#define EDDEXTSIZE              8
+#define EDDPARMSIZE             74
+
 #endif /* __XEN_EDD_H__ */


Attachment: x86-EFI-EDD.patch
Description: Text document

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.