Commit adae4313cdd891e5ab76c407134b69bd825220e4

Authored by Rob Clark
Committed by Alexander Graf
1 parent 9309a1b76c

efi_loader: flesh out device-path to text

It needs to handle more device-path node types, and also multiple levels
of path hierarchy.  To simplify this, initially construct utf8 string to
a temporary buffer, and then allocate the real utf16 buffer that is
returned.  This should be mostly for debugging or at least not critical-
path so an extra copy won't hurt, and is saner than the alternative.

Signed-off-by: Rob Clark <robdclark@gmail.com>
Signed-off-by: Alexander Graf <agraf@suse.de>

Showing 3 changed files with 181 additions and 63 deletions Side-by-side Diff

... ... @@ -304,6 +304,7 @@
304 304  
305 305 #define EFI_PNP_ID(ID) (u32)(((ID) << 16) | 0x41D0)
306 306 #define EISA_PNP_ID(ID) EFI_PNP_ID(ID)
  307 +#define EISA_PNP_NUM(ID) ((ID) >> 16)
307 308  
308 309 struct efi_device_path_acpi_path {
309 310 struct efi_device_path dp;
include/efi_loader.h
... ... @@ -80,6 +80,8 @@
80 80 extern const struct efi_console_control_protocol efi_console_control;
81 81 extern const struct efi_device_path_to_text_protocol efi_device_path_to_text;
82 82  
  83 +uint16_t *efi_dp_str(struct efi_device_path *dp);
  84 +
83 85 extern const efi_guid_t efi_guid_console_control;
84 86 extern const efi_guid_t efi_guid_device_path;
85 87 extern const efi_guid_t efi_guid_loaded_image;
lib/efi_loader/efi_device_path_to_text.c
... ... @@ -15,81 +15,196 @@
15 15 const efi_guid_t efi_guid_device_path_to_text_protocol =
16 16 EFI_DEVICE_PATH_TO_TEXT_PROTOCOL_GUID;
17 17  
18   -static uint16_t *efi_convert_device_node_to_text(
19   - struct efi_device_path *device_node,
20   - bool display_only,
21   - bool allow_shortcuts)
  18 +static char *dp_unknown(char *s, struct efi_device_path *dp)
22 19 {
23   - unsigned long buffer_size;
24   - efi_status_t r;
25   - uint16_t *buffer = NULL;
26   - int i;
  20 + s += sprintf(s, "/UNKNOWN(%04x,%04x)", dp->type, dp->sub_type);
  21 + return s;
  22 +}
27 23  
28   - switch (device_node->type) {
29   - case DEVICE_PATH_TYPE_END:
30   - return NULL;
31   - case DEVICE_PATH_TYPE_MESSAGING_DEVICE:
32   - switch (device_node->sub_type) {
33   - case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: {
34   - struct efi_device_path_mac_addr *dp =
35   - (struct efi_device_path_mac_addr *)device_node;
  24 +static char *dp_hardware(char *s, struct efi_device_path *dp)
  25 +{
  26 + switch (dp->sub_type) {
  27 + case DEVICE_PATH_SUB_TYPE_VENDOR: {
  28 + struct efi_device_path_vendor *vdp =
  29 + (struct efi_device_path_vendor *)dp;
  30 + s += sprintf(s, "/VenHw(%pUl)", &vdp->guid);
  31 + break;
  32 + }
  33 + default:
  34 + s = dp_unknown(s, dp);
  35 + break;
  36 + }
  37 + return s;
  38 +}
36 39  
37   - if (dp->if_type != 0 && dp->if_type != 1)
38   - break;
39   - r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES,
40   - 2 * MAC_OUTPUT_LEN,
41   - (void **)&buffer);
42   - if (r != EFI_SUCCESS)
43   - return NULL;
44   - sprintf((char *)buffer,
45   - "MAC(%02x%02x%02x%02x%02x%02x,0x%1x)",
46   - dp->mac.addr[0], dp->mac.addr[1],
47   - dp->mac.addr[2], dp->mac.addr[3],
48   - dp->mac.addr[4], dp->mac.addr[5],
49   - dp->if_type);
50   - for (i = MAC_OUTPUT_LEN - 1; i >= 0; --i)
51   - buffer[i] = ((uint8_t *)buffer)[i];
  40 +static char *dp_acpi(char *s, struct efi_device_path *dp)
  41 +{
  42 + switch (dp->sub_type) {
  43 + case DEVICE_PATH_SUB_TYPE_ACPI_DEVICE: {
  44 + struct efi_device_path_acpi_path *adp =
  45 + (struct efi_device_path_acpi_path *)dp;
  46 + s += sprintf(s, "/Acpi(PNP%04x", EISA_PNP_NUM(adp->hid));
  47 + if (adp->uid)
  48 + s += sprintf(s, ",%d", adp->uid);
  49 + s += sprintf(s, ")");
  50 + break;
  51 + }
  52 + default:
  53 + s = dp_unknown(s, dp);
  54 + break;
  55 + }
  56 + return s;
  57 +}
  58 +
  59 +static char *dp_msging(char *s, struct efi_device_path *dp)
  60 +{
  61 + switch (dp->sub_type) {
  62 + case DEVICE_PATH_SUB_TYPE_MSG_USB: {
  63 + struct efi_device_path_usb *udp =
  64 + (struct efi_device_path_usb *)dp;
  65 + s += sprintf(s, "/Usb(0x%x,0x%x)", udp->parent_port_number,
  66 + udp->usb_interface);
  67 + break;
  68 + }
  69 + case DEVICE_PATH_SUB_TYPE_MSG_MAC_ADDR: {
  70 + struct efi_device_path_mac_addr *mdp =
  71 + (struct efi_device_path_mac_addr *)dp;
  72 +
  73 + if (mdp->if_type != 0 && mdp->if_type != 1)
52 74 break;
53   - }
54   - }
  75 +
  76 + s += sprintf(s, "/MAC(%02x%02x%02x%02x%02x%02x,0x%1x)",
  77 + mdp->mac.addr[0], mdp->mac.addr[1],
  78 + mdp->mac.addr[2], mdp->mac.addr[3],
  79 + mdp->mac.addr[4], mdp->mac.addr[5],
  80 + mdp->if_type);
  81 +
55 82 break;
56   - case DEVICE_PATH_TYPE_MEDIA_DEVICE:
57   - switch (device_node->sub_type) {
58   - case DEVICE_PATH_SUB_TYPE_FILE_PATH: {
59   - struct efi_device_path_file_path *fp =
60   - (struct efi_device_path_file_path *)device_node;
61   - buffer_size = device_node->length - 4;
62   - r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES,
63   - buffer_size, (void **) &buffer);
64   - if (r != EFI_SUCCESS)
65   - return NULL;
66   - memcpy(buffer, fp->str, buffer_size);
  83 + }
  84 + case DEVICE_PATH_SUB_TYPE_MSG_USB_CLASS: {
  85 + struct efi_device_path_usb_class *ucdp =
  86 + (struct efi_device_path_usb_class *)dp;
  87 +
  88 + s += sprintf(s, "/USBClass(%x,%x,%x,%x,%x)",
  89 + ucdp->vendor_id, ucdp->product_id,
  90 + ucdp->device_class, ucdp->device_subclass,
  91 + ucdp->device_protocol);
  92 +
  93 + break;
  94 + }
  95 + case DEVICE_PATH_SUB_TYPE_MSG_SD:
  96 + case DEVICE_PATH_SUB_TYPE_MSG_MMC: {
  97 + const char *typename =
  98 + (dp->sub_type == DEVICE_PATH_SUB_TYPE_MSG_SD) ?
  99 + "SDCard" : "MMC";
  100 + struct efi_device_path_sd_mmc_path *sddp =
  101 + (struct efi_device_path_sd_mmc_path *)dp;
  102 + s += sprintf(s, "/%s(Slot%u)", typename, sddp->slot_number);
  103 + break;
  104 + }
  105 + default:
  106 + s = dp_unknown(s, dp);
  107 + break;
  108 + }
  109 + return s;
  110 +}
  111 +
  112 +static char *dp_media(char *s, struct efi_device_path *dp)
  113 +{
  114 + switch (dp->sub_type) {
  115 + case DEVICE_PATH_SUB_TYPE_HARD_DRIVE_PATH: {
  116 + struct efi_device_path_hard_drive_path *hddp =
  117 + (struct efi_device_path_hard_drive_path *)dp;
  118 + void *sig = hddp->partition_signature;
  119 +
  120 + switch (hddp->signature_type) {
  121 + case SIG_TYPE_MBR:
  122 + s += sprintf(s, "/HD(Part%d,Sig%08x)",
  123 + hddp->partition_number,
  124 + *(uint32_t *)sig);
67 125 break;
  126 + case SIG_TYPE_GUID:
  127 + s += sprintf(s, "/HD(Part%d,Sig%pUl)",
  128 + hddp->partition_number, sig);
  129 + default:
  130 + s += sprintf(s, "/HD(Part%d,MBRType=%02x,SigType=%02x)",
  131 + hddp->partition_number, hddp->partmap_type,
  132 + hddp->signature_type);
68 133 }
69   - }
  134 +
70 135 break;
71 136 }
  137 + case DEVICE_PATH_SUB_TYPE_CDROM_PATH: {
  138 + struct efi_device_path_cdrom_path *cddp =
  139 + (struct efi_device_path_cdrom_path *)dp;
  140 + s += sprintf(s, "/CDROM(0x%x)", cddp->boot_entry);
  141 + break;
  142 + }
  143 + case DEVICE_PATH_SUB_TYPE_FILE_PATH: {
  144 + struct efi_device_path_file_path *fp =
  145 + (struct efi_device_path_file_path *)dp;
  146 + int slen = (dp->length - sizeof(*dp)) / 2;
  147 + s += sprintf(s, "/%-*ls", slen, fp->str);
  148 + break;
  149 + }
  150 + default:
  151 + s = dp_unknown(s, dp);
  152 + break;
  153 + }
  154 + return s;
  155 +}
72 156  
73   - /*
74   - * For all node types that we do not yet support return
75   - * 'UNKNOWN(type,subtype)'.
76   - */
77   - if (!buffer) {
78   - r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES,
79   - 2 * UNKNOWN_OUTPUT_LEN,
80   - (void **)&buffer);
81   - if (r != EFI_SUCCESS)
82   - return NULL;
83   - sprintf((char *)buffer,
84   - "UNKNOWN(%04x,%04x)",
85   - device_node->type,
86   - device_node->sub_type);
87   - for (i = UNKNOWN_OUTPUT_LEN - 1; i >= 0; --i)
88   - buffer[i] = ((uint8_t *)buffer)[i];
  157 +static uint16_t *efi_convert_device_node_to_text(
  158 + struct efi_device_path *dp,
  159 + bool display_only,
  160 + bool allow_shortcuts)
  161 +{
  162 + unsigned long len;
  163 + efi_status_t r;
  164 + char buf[512]; /* this ought be be big enough for worst case */
  165 + char *str = buf;
  166 + uint16_t *out;
  167 +
  168 + while (dp) {
  169 + switch (dp->type) {
  170 + case DEVICE_PATH_TYPE_HARDWARE_DEVICE:
  171 + str = dp_hardware(str, dp);
  172 + break;
  173 + case DEVICE_PATH_TYPE_ACPI_DEVICE:
  174 + str = dp_acpi(str, dp);
  175 + break;
  176 + case DEVICE_PATH_TYPE_MESSAGING_DEVICE:
  177 + str = dp_msging(str, dp);
  178 + break;
  179 + case DEVICE_PATH_TYPE_MEDIA_DEVICE:
  180 + str = dp_media(str, dp);
  181 + break;
  182 + default:
  183 + str = dp_unknown(str, dp);
  184 + }
  185 +
  186 + dp = efi_dp_next(dp);
89 187 }
90 188  
91   - return buffer;
  189 + *str++ = '\0';
  190 +
  191 + len = str - buf;
  192 + r = efi_allocate_pool(EFI_ALLOCATE_ANY_PAGES, 2 * len, (void **)&out);
  193 + if (r != EFI_SUCCESS)
  194 + return NULL;
  195 +
  196 + ascii2unicode(out, buf);
  197 + out[len - 1] = 0;
  198 +
  199 + return out;
92 200 }
  201 +
  202 +/* helper for debug prints.. efi_free_pool() the result. */
  203 +uint16_t *efi_dp_str(struct efi_device_path *dp)
  204 +{
  205 + return efi_convert_device_node_to_text(dp, true, true);
  206 +}
  207 +
93 208  
94 209 static uint16_t EFIAPI *efi_convert_device_node_to_text_ext(
95 210 struct efi_device_path *device_node,