#include "smbios.h"
#include "util.h"
+/* Validate the descriptor macros a bit that they match our expectations */
+assert_cc(DEVICE_DESCRIPTOR_DEVICETREE == UINT32_C(0x1000001C));
+assert_cc(DEVICE_SIZE_FROM_DESCRIPTOR(DEVICE_DESCRIPTOR_DEVICETREE) == sizeof(Device));
+assert_cc(DEVICE_TYPE_FROM_DESCRIPTOR(DEVICE_DESCRIPTOR_DEVICETREE) == DEVICE_TYPE_DEVICETREE);
+
/**
* smbios_to_hashable_string() - Convert ascii smbios string to stripped char16_t.
*/
/* Count devices and check validity */
for (; (n_devices + 1) * sizeof(*devices) < hwid_length;) {
- if (devices[n_devices].struct_size == 0)
+
+ if (devices[n_devices].descriptor == DEVICE_DESCRIPTOR_EOL)
break;
- if (devices[n_devices].struct_size != sizeof(*devices))
+ if (devices[n_devices].descriptor != DEVICE_DESCRIPTOR_DEVICETREE)
return EFI_UNSUPPORTED;
n_devices++;
}
#pragma once
#include "efi.h"
-
#include "chid-fundamental.h"
+/* 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 */
+
+ /* Maybe later additional types for:
+ * - CoCo Bring-Your-Own-Firmware
+ * - ACPI DSDT Overrides
+ * - … */
+};
+
+#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_EOL UINT32_C(0)
+
typedef struct Device {
- uint32_t struct_size; /* = sizeof(struct Device), or 0 for EOL */
- uint32_t name_offset; /* nul-terminated string or 0 if not present */
- uint32_t compatible_offset; /* nul-terminated string or 0 if not present */
+ 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;
+ /* 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(sizeof(Device) == 28);
+
static inline const char* device_get_name(const void *base, const Device *device) {
- return device->name_offset == 0 ? NULL : (const char *) ((const uint8_t *) base + device->name_offset);
+ if (device->descriptor != DEVICE_DESCRIPTOR_DEVICETREE)
+ return NULL;
+
+ return device->devicetree.name_offset == 0 ? NULL : (const char *) ((const uint8_t *) base + device->devicetree.name_offset);
}
static inline const char* device_get_compatible(const void *base, const Device *device) {
- return device->compatible_offset == 0 ? NULL : (const char *) ((const uint8_t *) base + device->compatible_offset);
+ if (device->descriptor != DEVICE_DESCRIPTOR_DEVICETREE)
+ return NULL;
+
+ return device->devicetree.compatible_offset == 0 ? NULL : (const char *) ((const uint8_t *) base + device->devicetree.compatible_offset);
}
EFI_STATUS chid_match(const void *chids_buffer, size_t chids_length, const Device **ret_device);