123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278 |
- /*
- * gudt.h - Grand Unified Device Tree
- * https://gitlab.com/bztsrc/gudt
- *
- * Copyright (C) 2024 bzt, MIT license
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
- * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
- * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- * @brief Structures to work with GUDT blobs
- */
- #ifndef GUDT_H
- #define GUDT_H 1
- #ifdef __cplusplus
- extern "C" {
- #endif
- #ifndef _STDINT_H
- #include <stdint.h>
- #endif
- #define GUDT_MAGIC "GUDT"
- #ifdef _MSC_VER
- #pragma pack(push)
- #pragma pack(1)
- #define _PACK
- #else
- #define _PACK __attribute__((packed))
- #endif
- typedef struct {
- uint8_t magic[4]; /* magic GUDT */
- uint16_t hdrsize; /* 8 + string table's size */
- uint16_t numnodes; /* number of nodes */
- } _PACK gudt_hdr_t;
- /* type field */
- enum { GUDT_T_DEVICE, GUDT_T_CPUCORE, GUDT_T_DMA, GUDT_T_IRQ, GUDT_T_INTC, GUDT_T_PINS, GUDT_T_LEDS, GUDT_T_CLOCKS, GUDT_T_SENSORS,
- GUDT_BUTTONS, GUDT_T_AMPER, GUDT_T_VOLT, GUDT_T_THERMAL, GUDT_T_FREQ, GUDT_T_L0CACHE, GUDT_T_L1CACHE, GUDT_T_L2CACHE,
- GUDT_T_L3CACHE, /* unassigned */
- GUDT_T_EDID = 0xd7, GUDT_T_FBPTR, GUDT_T_FBDIM, GUDT_T_MODULE, GUDT_T_CMDLINE, GUDT_T_DEFAULT,
- GUDT_T_NVSMEM, GUDT_T_RESVMEM, GUDT_T_RAM,
- /* top 32 entries must match ACPI region space */
- GUDT_T_MMIO = 0xe0, GUDT_T_IOPORT, GUDT_T_PCI, GUDT_T_EC, GUDT_T_SMB, GUDT_T_NVRAM, GUDT_T_PCIBAR, GUDT_T_IPMI,
- GUDT_T_GPIO, GUDT_T_GSB, GUDT_T_PCC };
- /* category field, must match pci.ids class */
- enum { GUDT_C_UNKNOWN, GUDT_T_STORAGE, GUDT_C_NETWORK, GUDT_C_DISPLAY, GUDT_C_MULTIMEDIA, GUDT_C_MEMORY, GUDT_C_BRIDGE,
- GUDT_C_COMM, GUDT_C_GENERIC, GUDT_C_INPUT, GUDT_C_DOCK, GUDT_C_PROCESSOR, GUDT_C_SERIAL, GUDT_C_WIRELESS, GUDT_C_INTELLIGENT,
- GUDT_C_SATELLITE, GUDT_C_ENCRYPTION, GUDT_C_SIGNAL, GUDT_C_ACCEL, GUDT_C_NONESSENTIAL, GUDT_C_MACHINE = 0xff };
- /* device field but only when category is GUDT_C_MACHINE, must match ACPI PM Profiles */
- enum { GUDT_D_UNSPECIFIED, GUDT_D_DESKTOP, GUDT_D_MOBILE, GUDT_D_WORKSTATION, GUDT_D_ENTERPRISE, GUDT_D_SOHO, GUDT_D_APPLIANCE,
- GUDT_D_PERFORMANCE, GUDT_D_TABLET };
- /* stored in flags */
- #define GUDT_F_UNIT(x) (1<<((x)&15))
- #define GUDT_F_DATA(x) (((x)>>4)&15)
- #define GUDT_F_INDIRECT 0x0f
- /* device node */
- typedef struct {
- uint8_t type; /* must be 0, GUDT_T_DEVICE */
- uint8_t category; /* PCI device class, GUDT_C_x */
- uint16_t parent; /* parent node */
- uint16_t driver; /* string table offset, device driver name */
- uint16_t alternative; /* string table offset, alternative driver name */
- uint16_t name; /* string table offset, device's unique name */
- uint16_t device; /* PCI device sub-class (or GUDT_D_x) */
- uint16_t vendor; /* PCI vendor code */
- uint16_t model; /* PCI device code */
- } _PACK gudt_device_t;
- /* resource node */
- typedef struct {
- uint8_t type; /* must not be 0, any other GUDT_T_x */
- uint8_t flags; /* bit 0..3: resource's unit size */
- uint16_t parent; /* parent node */
- union { /* resource descriptor */
- /* flags bit 4..7: 0 */
- struct { uint32_t size; uint64_t base; } _PACK p;
- /* flags bit 4..7: num items */
- struct { uint8_t data[12]; } _PACK b;
- struct { uint16_t data[6]; } _PACK w;
- struct { uint32_t data[3]; } _PACK d;
- struct { uint32_t pad; uint64_t data[1]; } _PACK q;
- } _PACK r;
- } _PACK gudt_node_t;
- #ifdef _MSC_VER
- #pragma pack(pop)
- #endif
- #undef _PACK
- /**
- * Utility function to uncompress a packed GUDT blob and swap bytes on big endian machines. It *DOES NOT* use libc nor
- * allocate memory, so the provided destination buffer must be at least src.hdrsize + 8 + src.numnodes * 16 bytes big.
- * Returns 0 on error, 1 on success, and 2 when no unpacking was done (you can use src as dst).
- */
- int gudt_unpack(const gudt_hdr_t *src, gudt_hdr_t *dst);
- /**
- * Function to return a specific resource of a specific device. Returns NULL if resource not found.
- */
- gudt_node_t *gudt_find(const gudt_hdr_t *hdr, const char *driver, const char *name, uint8_t type);
- #ifdef GUDT_IMPLEMENTATION
- #if defined(GUDT_BIGENDIAN) || defined(GUDT_NEEDCONV)
- void gudt_bswap(gudt_hdr_t *hdr)
- {
- gudt_device_t *d;
- gudt_node_t *n;
- uint8_t *p = (uint8_t*)hdr;
- uint32_t i, j, u, l;
- hdr->hdrsize = __builtin_bswap16(hdr->hdrsize); hdr->numnodes = __builtin_bswap16(hdr->numnodes);
- n = (gudt_node_t*)(p + ((hdr->hdrsize + 7) & ~7));
- for(i = 0; i < hdr->numnodes; i++, n++) {
- n->parent = __builtin_bswap16(n->parent);
- if(n->type == GUDT_T_DEVICE) {
- d = (gudt_device_t*)n;
- d->driver = __builtin_bswap16(d->driver); d->alternative = __builtin_bswap16(d->alternative);
- d->name = __builtin_bswap16(d->name); d->device = __builtin_bswap16(d->device);
- d->vendor = __builtin_bswap16(d->vendor); d->model = __builtin_bswap16(d->model);
- } else {
- u = GUDT_F_UNIT(n->flags); l = GUDT_F_DATA(n->flags);
- if(!l || u == 8) { n->r.p.size = __builtin_bswap32(n->r.p.size); n->r.p.base = __builtin_bswap64(n->r.p.base); } else
- for(j = 0; j < l; j++)
- switch(u) {
- case 2: n->r.w.data[j] = __builtin_bswap16(n->r.w.data[j]); break;
- case 4: n->r.d.data[j] = __builtin_bswap32(n->r.d.data[j]); break;
- }
- }
- }
- }
- #endif
- typedef struct { uint32_t b, c, t; uint8_t *s, *d; uint16_t e[16], f[288], g[16], h[288]; } gudt_z_t;
- static void gudt_bt(uint16_t *t, uint16_t *r, const uint8_t *l, uint32_t n) {
- uint32_t i, s, o[16]; for(i = 0; i < 16; i++) { t[i] = 0; } for(i = 0; i < n; i++) t[(uint32_t)l[i]]++;
- for(s = 0, i = 0, t[0] = 0; i < 16; i++) { o[i] = s; s += t[i]; } for(i = 0; i < n; i++) if(l[i]) r[o[(uint32_t)l[i]]++] = i; }
- static int gudt_gb(gudt_z_t *d) { uint32_t b; if(!d->b--) { d->t = *d->s++; d->b = 7; } b = d->t & 1; d->t >>= 1; return b; }
- static uint32_t gudt_rb(gudt_z_t *d, uint32_t n, uint32_t b) {
- uint32_t v = 0, m, l; if(n) { l = 1 << n; for(m = 1; m < l; m <<= 1) if(gudt_gb(d)) v += m; } return v + b; }
- static int gudt_ds(gudt_z_t *d, uint16_t *t, uint16_t *r) {
- int s = 0, c = 0, l = 0; do { c = (c << 1) + gudt_gb(d); s += t[++l]; c -= t[l]; } while(c >= 0); return r[s + c]; }
- int gudt_de(uint8_t *src, uint8_t *dst, uint32_t siz) {
- static uint16_t m[30] = {3,4,5,6,7,8,9,10,11,13,15,17,19,23,27,31,35,43,51,59,67,83,99,115,131,163,195,227,258},
- n[30] = {1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577};
- static uint8_t c[] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
- uint8_t k[288+32], p;
- uint32_t i, l, x, y, z;
- int r = 2, s, t = -1, f = 0, o = 0;
- gudt_z_t d = { 0 };
- d.s = src; d.d = dst;
- do {
- do {
- if(t == -1) {
- again: f = gudt_gb(&d);
- t = gudt_rb(&d, 2, 0);
- switch(t) {
- case 1:
- for(i = 0; i < 7; i++) d.e[i] = 0;
- d.e[7] = 24; d.e[8] = 152; d.e[9] = 112;
- for(i = 0; i < 24; i++) d.f[i] = 256 + i;
- for(i = 0; i < 144; i++) d.f[24 + i] = i;
- for(i = 0; i < 8; i++) d.f[24 + 144 + i] = 280 + i;
- for(i = 0; i < 112; i++) d.f[24 + 144 + 8 + i] = 144 + i;
- for(i = 0; i < 5; i++) d.g[i] = 0;
- for(i = 0, d.g[5] = 32; i < 32; i++) d.h[i] = i;
- break;
- case 2:
- x = gudt_rb(&d, 5, 257); y = gudt_rb(&d, 5, 1); z = gudt_rb(&d, 4, 4);
- for(i = 0; i < 19; i++) k[i] = 0;
- for(i = 0; i < z; i++) k[c[i]] = gudt_rb(&d, 3, 0);
- gudt_bt(d.e, d.f, k, 19);
- for(i = 0; i < x + y;)
- switch((s = gudt_ds(&d, d.e, d.f))) {
- case 16: for(p = k[i - 1], l = gudt_rb(&d, 2, 3); l; l--) k[i++] = p; break;
- case 17: for(l = gudt_rb(&d, 3, 3); l; l--) k[i++] = 0; break;
- case 18: for(l = gudt_rb(&d, 7, 11); l; l--) k[i++] = 0; break;
- default: k[i++] = s; break;
- }
- gudt_bt(d.e, d.f, k, x); gudt_bt(d.g, d.h, k + x, y);
- break;
- }
- }
- switch(t) {
- case 0:
- if(!d.c) { d.c = 1 + (d.s[0] | (d.s[1] << 8)); d.s += 4; d.b = 0; }
- if(!--d.c) r = 1; else { *d.d++ = *d.s++; r = 0; }
- break;
- case 1: case 2:
- if(!d.c) {
- s = gudt_ds(&d, d.e, d.f);
- if(s < 256) { *d.d++ = s; r = 0; break; } else if(s == 256) { r = 1; break; }
- s -= 257; d.c = gudt_rb(&d, s < 4 || s > 27 ? 0 : ((s - 4) >> 2), m[s]);
- r = gudt_ds(&d, d.g, d.h); o = -gudt_rb(&d, r < 2 || r > 29 ? 0 : ((r - 2) >> 1), n[r]);
- }
- d.d[0] = d.d[o]; d.d++; d.c--; r = 0;
- break;
- default: return 0;
- }
- if(r == 1 && !f) goto again;
- if(r) break;
- } while(--siz);
- } while(!r);
- return r;
- }
- int gudt_unpack(const gudt_hdr_t *src, gudt_hdr_t *dst)
- {
- uint32_t i, size;
- uint8_t *strs = (uint8_t*)dst;
- int r = 2;
- if(!src || !dst || src->magic[0] != 'G' || src->magic[1] != 'U' || src->magic[2] != 'D') return 0;
- size = (((((uint8_t*)src)[4] | (((uint8_t*)src)[5] << 8)) + 7) & ~7) + ((((uint8_t*)src)[6] | (((uint8_t*)src)[7] << 8)) << 4);
- if(((uint8_t*)src)[8] == 0x78 && ((uint8_t*)src)[9] == 0xDA) {
- for(i = 0; i < 8; i++) strs[i] = ((uint8_t*)src)[i];
- r = gudt_de((uint8_t*)src + 10, strs + 8, size);
- }
- #ifdef GUDT_BIGENDIAN
- if(r && src->magic[3] != 'B') {
- if(r == 2) for(i = 0; i < size; i++) strs[i] = ((uint8_t*)src)[i];
- r = 1; strs[3] = 'B'; gudt_bswap(dst);
- }
- #endif
- return r;
- }
- gudt_node_t *gudt_find(const gudt_hdr_t *hdr, const char *driver, const char *name, uint8_t type)
- {
- gudt_device_t *d;
- gudt_node_t *n;
- uint32_t i, dl, nl;
- if(hdr && driver && name && hdr->magic[0] == 'G' && hdr->magic[1] == 'U' && hdr->magic[2] == 'D') {
- n = (gudt_node_t*)((uint8_t*)hdr + ((hdr->hdrsize + 7) & ~7));
- for(dl = 0; driver[dl]; dl++);
- for(nl = 0; name[nl]; nl++);
- for(i = 0; i < hdr->numnodes; i++)
- if(n[i].type == type && n[i].parent < hdr->numnodes && n[n[i].parent].type == GUDT_T_DEVICE) {
- d = (gudt_device_t*)&n[n[i].parent];
- if(d->name >= 8 && d->name < hdr->hdrsize && d->driver >= 8 && d->driver < hdr->hdrsize &&
- !memcmp((uint8_t*)hdr + d->name, name, nl + 1) && (!memcmp((uint8_t*)hdr + d->driver, driver, dl + 1) ||
- (d->alternative >= 8 && d->alternative < hdr->hdrsize &&
- !memcmp((uint8_t*)hdr + d->alternative, driver, dl + 1)))) return &n[i];
- }
- }
- return NULL;
- }
- #endif /* GUDT_IMPLEMENTATION */
- #ifdef __cplusplus
- }
- #endif
- #endif /* GUDT_H */
|