1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
|
/* SPDX-License-Identifier: BSD-3-Clause */
#pragma once
#include "efi.h"
#define CHID_TYPES_MAX 18
/* Any chids starting from EXTRA_CHID_BASE are non-standard and are subject to change and renumeration at any time */
#define EXTRA_CHID_BASE 15
typedef enum ChidSmbiosFields {
CHID_SMBIOS_MANUFACTURER,
CHID_SMBIOS_FAMILY,
CHID_SMBIOS_PRODUCT_NAME,
CHID_SMBIOS_PRODUCT_SKU,
CHID_SMBIOS_BASEBOARD_MANUFACTURER,
CHID_SMBIOS_BASEBOARD_PRODUCT,
CHID_SMBIOS_BIOS_VENDOR,
CHID_SMBIOS_BIOS_VERSION,
CHID_SMBIOS_BIOS_MAJOR,
CHID_SMBIOS_BIOS_MINOR,
CHID_SMBIOS_ENCLOSURE_TYPE,
CHID_EDID_PANEL,
_CHID_SMBIOS_FIELDS_MAX,
} ChidSmbiosFields;
extern const uint32_t chid_smbios_table[CHID_TYPES_MAX];
/* CHID (also called HWID by fwupd) is described at https://github.com/fwupd/fwupd/blob/main/docs/hwids.md */
void chid_calculate(const char16_t *const smbios_fields[static _CHID_SMBIOS_FIELDS_MAX], EFI_GUID ret_chids[static CHID_TYPES_MAX]);
/* A .hwids PE section consists of a series of 'Device' structures. A 'Device' structure binds a CHID to some
* resource, for now only Devicetree blobs. Designed to be extensible to other types of resources, should the
* need arise. The series of 'Device' structures is followed by some space for strings that can be referenced
* by offset by the Device structures. */
enum {
DEVICE_TYPE_DEVICETREE = 0x1, /* A devicetree blob */
DEVICE_TYPE_UEFI_FW = 0x2, /* A firmware blob */
/* Maybe later additional types for:
* - CoCo Bring-Your-Own-Firmware
* - ACPI DSDT Overrides
* - … */
_DEVICE_TYPE_MAX,
};
#define DEVICE_SIZE_FROM_DESCRIPTOR(u) ((uint32_t) (u) & UINT32_C(0x0FFFFFFF))
#define DEVICE_TYPE_FROM_DESCRIPTOR(u) ((uint32_t) (u) >> 28)
#define DEVICE_MAKE_DESCRIPTOR(type, size) (((uint32_t) (size) | ((uint32_t) type << 28)))
#define DEVICE_DESCRIPTOR_DEVICETREE DEVICE_MAKE_DESCRIPTOR(DEVICE_TYPE_DEVICETREE, sizeof(Device))
#define DEVICE_DESCRIPTOR_UEFI_FW DEVICE_MAKE_DESCRIPTOR(DEVICE_TYPE_UEFI_FW, sizeof(Device))
#define DEVICE_DESCRIPTOR_EOL UINT32_C(0)
typedef struct Device {
uint32_t descriptor; /* The highest four bit encode the type of entry, the other 28 bit encode the
* size of the structure. Use the macros above to generate or take apart this
* field. */
EFI_GUID chid;
union {
struct {
/* These offsets are relative to the beginning of the .hwids PE section. */
uint32_t name_offset; /* nul-terminated string or 0 if not present */
uint32_t compatible_offset; /* nul-terminated string or 0 if not present */
} devicetree;
struct {
/* Offsets are relative to the beginning of the .hwids PE section.
* They are nul-terminated strings when present or 0 if not present */
uint32_t name_offset; /* name or identifier for the firmware blob */
uint32_t fwid_offset; /* identifier to match a specific uefi firmware blob */
} uefi_fw;
/* fields for other descriptor types… */
};
} _packed_ Device;
/* Validate some offset, since the structure is API and src/ukify/ukify.py encodes them directly */
assert_cc(offsetof(Device, descriptor) == 0);
assert_cc(offsetof(Device, chid) == 4);
assert_cc(offsetof(Device, devicetree.name_offset) == 20);
assert_cc(offsetof(Device, devicetree.compatible_offset) == 24);
assert_cc(offsetof(Device, uefi_fw.name_offset) == 20);
assert_cc(offsetof(Device, uefi_fw.fwid_offset) == 24);
assert_cc(sizeof(Device) == 28);
static inline const char* device_get_name(const void *base, const Device *device) {
size_t off = 0;
switch (DEVICE_TYPE_FROM_DESCRIPTOR(device->descriptor)) {
case DEVICE_TYPE_DEVICETREE:
off = device->devicetree.name_offset;
break;
case DEVICE_TYPE_UEFI_FW:
off = device->uefi_fw.name_offset;
break;
default:
return NULL;
}
return off == 0 ? NULL : (const char *) ((const uint8_t *) base + off);
}
static inline const char* device_get_compatible(const void *base, const Device *device) {
size_t off = 0;
switch (DEVICE_TYPE_FROM_DESCRIPTOR(device->descriptor)) {
case DEVICE_TYPE_DEVICETREE:
off = device->devicetree.compatible_offset;
break;
default:
return NULL;
}
return off == 0 ? NULL : (const char *) ((const uint8_t *) base + off);
}
static inline const char* device_get_fwid(const void *base, const Device *device) {
size_t off = 0;
switch (DEVICE_TYPE_FROM_DESCRIPTOR(device->descriptor)) {
case DEVICE_TYPE_UEFI_FW:
off = device->uefi_fw.fwid_offset;
break;
default:
return NULL;
}
return off == 0 ? NULL : (const char *) ((const uint8_t *) base + off);
}
EFI_STATUS chid_match(const void *chids_buffer, size_t chids_length, uint32_t match_type, const Device **ret_device);
|