gudt.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. /*
  2. * gudt.h - Grand Unified Device Tree
  3. * https://gitlab.com/bztsrc/gudt
  4. *
  5. * Copyright (C) 2024 bzt, MIT license
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a copy
  8. * of this software and associated documentation files (the "Software"), to
  9. * deal in the Software without restriction, including without limitation the
  10. * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  11. * sell copies of the Software, and to permit persons to whom the Software is
  12. * furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included in
  15. * all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  18. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ANY
  20. * DEVELOPER OR DISTRIBUTOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  21. * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
  22. * IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  23. *
  24. * @brief Structures to work with GUDT blobs
  25. */
  26. #ifndef GUDT_H
  27. #define GUDT_H 1
  28. #ifdef __cplusplus
  29. extern "C" {
  30. #endif
  31. #ifndef _STDINT_H
  32. #include <stdint.h>
  33. #endif
  34. #define GUDT_MAGIC "GUDT"
  35. #ifdef _MSC_VER
  36. #pragma pack(push)
  37. #pragma pack(1)
  38. #define _PACK
  39. #else
  40. #define _PACK __attribute__((packed))
  41. #endif
  42. typedef struct {
  43. uint8_t magic[4]; /* magic GUDT */
  44. uint16_t hdrsize; /* 8 + string table's size */
  45. uint16_t numnodes; /* number of nodes */
  46. } _PACK gudt_hdr_t;
  47. /* type field */
  48. 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,
  49. GUDT_BUTTONS, GUDT_T_AMPER, GUDT_T_VOLT, GUDT_T_THERMAL, GUDT_T_FREQ, GUDT_T_L0CACHE, GUDT_T_L1CACHE, GUDT_T_L2CACHE,
  50. GUDT_T_L3CACHE, /* unassigned */
  51. GUDT_T_EDID = 0xd7, GUDT_T_FBPTR, GUDT_T_FBDIM, GUDT_T_MODULE, GUDT_T_CMDLINE, GUDT_T_DEFAULT,
  52. GUDT_T_NVSMEM, GUDT_T_RESVMEM, GUDT_T_RAM,
  53. /* top 32 entries must match ACPI region space */
  54. 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,
  55. GUDT_T_GPIO, GUDT_T_GSB, GUDT_T_PCC };
  56. /* category field, must match pci.ids class */
  57. enum { GUDT_C_UNKNOWN, GUDT_T_STORAGE, GUDT_C_NETWORK, GUDT_C_DISPLAY, GUDT_C_MULTIMEDIA, GUDT_C_MEMORY, GUDT_C_BRIDGE,
  58. GUDT_C_COMM, GUDT_C_GENERIC, GUDT_C_INPUT, GUDT_C_DOCK, GUDT_C_PROCESSOR, GUDT_C_SERIAL, GUDT_C_WIRELESS, GUDT_C_INTELLIGENT,
  59. GUDT_C_SATELLITE, GUDT_C_ENCRYPTION, GUDT_C_SIGNAL, GUDT_C_ACCEL, GUDT_C_NONESSENTIAL, GUDT_C_MACHINE = 0xff };
  60. /* device field but only when category is GUDT_C_MACHINE, must match ACPI PM Profiles */
  61. enum { GUDT_D_UNSPECIFIED, GUDT_D_DESKTOP, GUDT_D_MOBILE, GUDT_D_WORKSTATION, GUDT_D_ENTERPRISE, GUDT_D_SOHO, GUDT_D_APPLIANCE,
  62. GUDT_D_PERFORMANCE, GUDT_D_TABLET };
  63. /* stored in flags */
  64. #define GUDT_F_UNIT(x) (1<<((x)&15))
  65. #define GUDT_F_DATA(x) (((x)>>4)&15)
  66. #define GUDT_F_INDIRECT 0x0f
  67. /* device node */
  68. typedef struct {
  69. uint8_t type; /* must be 0, GUDT_T_DEVICE */
  70. uint8_t category; /* PCI device class, GUDT_C_x */
  71. uint16_t parent; /* parent node */
  72. uint16_t driver; /* string table offset, device driver name */
  73. uint16_t alternative; /* string table offset, alternative driver name */
  74. uint16_t name; /* string table offset, device's unique name */
  75. uint16_t device; /* PCI device sub-class (or GUDT_D_x) */
  76. uint16_t vendor; /* PCI vendor code */
  77. uint16_t model; /* PCI device code */
  78. } _PACK gudt_device_t;
  79. /* resource node */
  80. typedef struct {
  81. uint8_t type; /* must not be 0, any other GUDT_T_x */
  82. uint8_t flags; /* bit 0..3: resource's unit size */
  83. uint16_t parent; /* parent node */
  84. union { /* resource descriptor */
  85. /* flags bit 4..7: 0 */
  86. struct { uint32_t size; uint64_t base; } _PACK p;
  87. /* flags bit 4..7: num items */
  88. struct { uint8_t data[12]; } _PACK b;
  89. struct { uint16_t data[6]; } _PACK w;
  90. struct { uint32_t data[3]; } _PACK d;
  91. struct { uint32_t pad; uint64_t data[1]; } _PACK q;
  92. } _PACK r;
  93. } _PACK gudt_node_t;
  94. #ifdef _MSC_VER
  95. #pragma pack(pop)
  96. #endif
  97. #undef _PACK
  98. /**
  99. * Utility function to uncompress a packed GUDT blob and swap bytes on big endian machines. It *DOES NOT* use libc nor
  100. * allocate memory, so the provided destination buffer must be at least src.hdrsize + 8 + src.numnodes * 16 bytes big.
  101. * Returns 0 on error, 1 on success, and 2 when no unpacking was done (you can use src as dst).
  102. */
  103. int gudt_unpack(const gudt_hdr_t *src, gudt_hdr_t *dst);
  104. /**
  105. * Function to return a specific resource of a specific device. Returns NULL if resource not found.
  106. */
  107. gudt_node_t *gudt_find(const gudt_hdr_t *hdr, const char *driver, const char *name, uint8_t type);
  108. #ifdef GUDT_IMPLEMENTATION
  109. #if defined(GUDT_BIGENDIAN) || defined(GUDT_NEEDCONV)
  110. void gudt_bswap(gudt_hdr_t *hdr)
  111. {
  112. gudt_device_t *d;
  113. gudt_node_t *n;
  114. uint8_t *p = (uint8_t*)hdr;
  115. uint32_t i, j, u, l;
  116. hdr->hdrsize = __builtin_bswap16(hdr->hdrsize); hdr->numnodes = __builtin_bswap16(hdr->numnodes);
  117. n = (gudt_node_t*)(p + ((hdr->hdrsize + 7) & ~7));
  118. for(i = 0; i < hdr->numnodes; i++, n++) {
  119. n->parent = __builtin_bswap16(n->parent);
  120. if(n->type == GUDT_T_DEVICE) {
  121. d = (gudt_device_t*)n;
  122. d->driver = __builtin_bswap16(d->driver); d->alternative = __builtin_bswap16(d->alternative);
  123. d->name = __builtin_bswap16(d->name); d->device = __builtin_bswap16(d->device);
  124. d->vendor = __builtin_bswap16(d->vendor); d->model = __builtin_bswap16(d->model);
  125. } else {
  126. u = GUDT_F_UNIT(n->flags); l = GUDT_F_DATA(n->flags);
  127. 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
  128. for(j = 0; j < l; j++)
  129. switch(u) {
  130. case 2: n->r.w.data[j] = __builtin_bswap16(n->r.w.data[j]); break;
  131. case 4: n->r.d.data[j] = __builtin_bswap32(n->r.d.data[j]); break;
  132. }
  133. }
  134. }
  135. }
  136. #endif
  137. typedef struct { uint32_t b, c, t; uint8_t *s, *d; uint16_t e[16], f[288], g[16], h[288]; } gudt_z_t;
  138. static void gudt_bt(uint16_t *t, uint16_t *r, const uint8_t *l, uint32_t n) {
  139. 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]]++;
  140. 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; }
  141. 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; }
  142. static uint32_t gudt_rb(gudt_z_t *d, uint32_t n, uint32_t b) {
  143. 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; }
  144. static int gudt_ds(gudt_z_t *d, uint16_t *t, uint16_t *r) {
  145. 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]; }
  146. int gudt_de(uint8_t *src, uint8_t *dst, uint32_t siz) {
  147. 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},
  148. 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};
  149. static uint8_t c[] = {16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15};
  150. uint8_t k[288+32], p;
  151. uint32_t i, l, x, y, z;
  152. int r = 2, s, t = -1, f = 0, o = 0;
  153. gudt_z_t d = { 0 };
  154. d.s = src; d.d = dst;
  155. do {
  156. do {
  157. if(t == -1) {
  158. again: f = gudt_gb(&d);
  159. t = gudt_rb(&d, 2, 0);
  160. switch(t) {
  161. case 1:
  162. for(i = 0; i < 7; i++) d.e[i] = 0;
  163. d.e[7] = 24; d.e[8] = 152; d.e[9] = 112;
  164. for(i = 0; i < 24; i++) d.f[i] = 256 + i;
  165. for(i = 0; i < 144; i++) d.f[24 + i] = i;
  166. for(i = 0; i < 8; i++) d.f[24 + 144 + i] = 280 + i;
  167. for(i = 0; i < 112; i++) d.f[24 + 144 + 8 + i] = 144 + i;
  168. for(i = 0; i < 5; i++) d.g[i] = 0;
  169. for(i = 0, d.g[5] = 32; i < 32; i++) d.h[i] = i;
  170. break;
  171. case 2:
  172. x = gudt_rb(&d, 5, 257); y = gudt_rb(&d, 5, 1); z = gudt_rb(&d, 4, 4);
  173. for(i = 0; i < 19; i++) k[i] = 0;
  174. for(i = 0; i < z; i++) k[c[i]] = gudt_rb(&d, 3, 0);
  175. gudt_bt(d.e, d.f, k, 19);
  176. for(i = 0; i < x + y;)
  177. switch((s = gudt_ds(&d, d.e, d.f))) {
  178. case 16: for(p = k[i - 1], l = gudt_rb(&d, 2, 3); l; l--) k[i++] = p; break;
  179. case 17: for(l = gudt_rb(&d, 3, 3); l; l--) k[i++] = 0; break;
  180. case 18: for(l = gudt_rb(&d, 7, 11); l; l--) k[i++] = 0; break;
  181. default: k[i++] = s; break;
  182. }
  183. gudt_bt(d.e, d.f, k, x); gudt_bt(d.g, d.h, k + x, y);
  184. break;
  185. }
  186. }
  187. switch(t) {
  188. case 0:
  189. if(!d.c) { d.c = 1 + (d.s[0] | (d.s[1] << 8)); d.s += 4; d.b = 0; }
  190. if(!--d.c) r = 1; else { *d.d++ = *d.s++; r = 0; }
  191. break;
  192. case 1: case 2:
  193. if(!d.c) {
  194. s = gudt_ds(&d, d.e, d.f);
  195. if(s < 256) { *d.d++ = s; r = 0; break; } else if(s == 256) { r = 1; break; }
  196. s -= 257; d.c = gudt_rb(&d, s < 4 || s > 27 ? 0 : ((s - 4) >> 2), m[s]);
  197. r = gudt_ds(&d, d.g, d.h); o = -gudt_rb(&d, r < 2 || r > 29 ? 0 : ((r - 2) >> 1), n[r]);
  198. }
  199. d.d[0] = d.d[o]; d.d++; d.c--; r = 0;
  200. break;
  201. default: return 0;
  202. }
  203. if(r == 1 && !f) goto again;
  204. if(r) break;
  205. } while(--siz);
  206. } while(!r);
  207. return r;
  208. }
  209. int gudt_unpack(const gudt_hdr_t *src, gudt_hdr_t *dst)
  210. {
  211. uint32_t i, size;
  212. uint8_t *strs = (uint8_t*)dst;
  213. int r = 2;
  214. if(!src || !dst || src->magic[0] != 'G' || src->magic[1] != 'U' || src->magic[2] != 'D') return 0;
  215. size = (((((uint8_t*)src)[4] | (((uint8_t*)src)[5] << 8)) + 7) & ~7) + ((((uint8_t*)src)[6] | (((uint8_t*)src)[7] << 8)) << 4);
  216. if(((uint8_t*)src)[8] == 0x78 && ((uint8_t*)src)[9] == 0xDA) {
  217. for(i = 0; i < 8; i++) strs[i] = ((uint8_t*)src)[i];
  218. r = gudt_de((uint8_t*)src + 10, strs + 8, size);
  219. }
  220. #ifdef GUDT_BIGENDIAN
  221. if(r && src->magic[3] != 'B') {
  222. if(r == 2) for(i = 0; i < size; i++) strs[i] = ((uint8_t*)src)[i];
  223. r = 1; strs[3] = 'B'; gudt_bswap(dst);
  224. }
  225. #endif
  226. return r;
  227. }
  228. gudt_node_t *gudt_find(const gudt_hdr_t *hdr, const char *driver, const char *name, uint8_t type)
  229. {
  230. gudt_device_t *d;
  231. gudt_node_t *n;
  232. uint32_t i, dl, nl;
  233. if(hdr && driver && name && hdr->magic[0] == 'G' && hdr->magic[1] == 'U' && hdr->magic[2] == 'D') {
  234. n = (gudt_node_t*)((uint8_t*)hdr + ((hdr->hdrsize + 7) & ~7));
  235. for(dl = 0; driver[dl]; dl++);
  236. for(nl = 0; name[nl]; nl++);
  237. for(i = 0; i < hdr->numnodes; i++)
  238. if(n[i].type == type && n[i].parent < hdr->numnodes && n[n[i].parent].type == GUDT_T_DEVICE) {
  239. d = (gudt_device_t*)&n[n[i].parent];
  240. if(d->name >= 8 && d->name < hdr->hdrsize && d->driver >= 8 && d->driver < hdr->hdrsize &&
  241. !memcmp((uint8_t*)hdr + d->name, name, nl + 1) && (!memcmp((uint8_t*)hdr + d->driver, driver, dl + 1) ||
  242. (d->alternative >= 8 && d->alternative < hdr->hdrsize &&
  243. !memcmp((uint8_t*)hdr + d->alternative, driver, dl + 1)))) return &n[i];
  244. }
  245. }
  246. return NULL;
  247. }
  248. #endif /* GUDT_IMPLEMENTATION */
  249. #ifdef __cplusplus
  250. }
  251. #endif
  252. #endif /* GUDT_H */