devpath1.c revision 1.4 1 /* $NetBSD: devpath1.c,v 1.4 2025/03/02 00:23:59 riastradh Exp $ */
2
3 /*
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
14 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23 * SUCH DAMAGE.
24 */
25
26 #include <sys/cdefs.h>
27 #ifndef lint
28 __RCSID("$NetBSD: devpath1.c,v 1.4 2025/03/02 00:23:59 riastradh Exp $");
29 #endif /* not lint */
30
31 #include <sys/uuid.h>
32
33 #include <assert.h>
34 #include <stdio.h>
35 #include <util.h>
36
37 #include "defs.h"
38 #include "devpath.h"
39 #include "devpath1.h"
40 #include "utils.h"
41
42 #define easprintf (size_t)easprintf
43
44 /************************************************************************
45 * Type 1 - PCI Device Path
46 ************************************************************************/
47
48 /*
49 * XXX: I can't find this GUID documented anywhere online. I snarfed
50 * it from
51 * https://github.com/rhboot/efivar::efivar-main/src/include/efivar/efivar-dp.h
52 * Comment out the define if you don't want to use it.
53 */
54 /* Used in subtype 4 */
55 #if 1
56 #define EFI_EDD10_PATH_GUID \
57 ((uuid_t){0xcf31fac5,0xc24e,0x11d2,0x85,0xf3, \
58 {0x00,0xa0,0xc9,0x3e,0xc9,0x3b}})
59 #endif
60
61 #define EFI_MEMORY_TYPE \
62 _X(ReservedMemoryType) \
63 _X(LoaderCode) \
64 _X(LoaderData) \
65 _X(BootServicesCode) \
66 _X(BootServicesData) \
67 _X(RuntimeServicesCode) \
68 _X(RuntimeServicesData) \
69 _X(ConventionalMemory) \
70 _X(UnusableMemory) \
71 _X(ACPIReclaimMemory) \
72 _X(ACPIMemoryNVS) \
73 _X(MemoryMappedIO) \
74 _X(MemoryMappedIOPortSpace) \
75 _X(PalCode) \
76 _X(PersistentMemory) \
77 _X(UnacceptedMemoryType) \
78 _X(MaxMemoryTyp)
79
80 typedef enum {
81 #define _X(n) Efi ## n,
82 EFI_MEMORY_TYPE
83 #undef _X
84 } EfiMemoryType_t;
85
86 static const char *
87 efi_memory_type_name(EfiMemoryType_t t)
88 {
89 static const char *memtype[] = {
90 #define _X(n) #n,
91 EFI_MEMORY_TYPE
92 #undef _X
93 };
94
95 if (t >= __arraycount(memtype))
96 return "Unknown";
97
98 return memtype[t];
99 }
100
101 /****************************************/
102
103 static inline void
104 devpath_hw_pci(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
105 { /* See 10.3.2.2 */
106 struct { /* Sub-Type 1 */
107 devpath_t hdr; /* Length = 6 */
108 uint8_t FunctionNum;
109 uint8_t DeviceNum;
110 } __packed *p = (void *)dp;
111 __CTASSERT(sizeof(*p) == 6);
112
113 path->sz = easprintf(&path->cp, "Pci(0x%x,0x%x)",
114 p->DeviceNum, p->FunctionNum);
115
116 if (dbg != NULL) {
117 dbg->sz = easprintf(&dbg->cp,
118 DEVPATH_FMT_HDR
119 DEVPATH_FMT(FunctionNum: %u\n)
120 DEVPATH_FMT(DeviceNum: %u\n),
121 DEVPATH_DAT_HDR(dp),
122 p->FunctionNum,
123 p->DeviceNum);
124 }
125 }
126
127 static inline void
128 devpath_hw_pccard(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
129 { /* See 10.3.2.2 */
130 struct { /* Sub-Type 2 */
131 devpath_t hdr; /* Length = 5 */
132 uint8_t FunctionNum;
133 } __packed *p = (void *)dp;
134 __CTASSERT(sizeof(*p) == 5);
135
136 path->sz = easprintf(&path->cp, "PcCard(0x%x)", p->FunctionNum);
137
138 if (dbg != NULL) {
139 dbg->sz = easprintf(&dbg->cp,
140 DEVPATH_FMT_HDR
141 DEVPATH_FMT(FunctionNum: %u\n),
142 DEVPATH_DAT_HDR(dp),
143 p->FunctionNum);
144 }
145 }
146
147 static inline void
148 devpath_hw_memmap(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
149 { /* See 10.3.2.3 */
150 struct { /* Sub-Type 3 */
151 devpath_t hdr; /* Length = 24 */
152 uint32_t MemoryType;
153 uint64_t StartAddress;
154 uint64_t EndAddress;
155 } __packed *p = (void *)dp;
156 __CTASSERT(sizeof(*p) == 24);
157 const char *typename;
158
159 typename = efi_memory_type_name(p->MemoryType);
160
161 path->sz = easprintf(&path->cp, "MemMap(%s,0x%016" PRIx64
162 ",0x%016" PRIx64 ")", typename,
163 p->StartAddress, p->EndAddress);
164
165 if (dbg != NULL) {
166 dbg->sz = easprintf(&dbg->cp,
167 DEVPATH_FMT_HDR
168 DEVPATH_FMT(MemoryType: 0x%08x(%s)\n)
169 DEVPATH_FMT(StartAddress:) " 0x%016" PRIx64 "\n"
170 DEVPATH_FMT(EndAddress:) " 0x%016" PRIx64 "\n",
171 DEVPATH_DAT_HDR(dp),
172 p->MemoryType, typename,
173 p->StartAddress,
174 p->EndAddress);
175
176 }
177 }
178
179 #ifdef EFI_EDD10_PATH_GUID
180 static inline void
181 devpath_hw_edd10(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
182 { /* See unknown - snarfed from efivar-main.zip */
183 struct { /* Sub-Type 4 */
184 devpath_t hdr; /* Length = 24 */
185 uuid_t GUID;
186 uint32_t devnum;
187 } __packed *p = (void *)dp;
188 __CTASSERT(sizeof(*p) == 24);
189
190 assert(p->hdr.Length == 24);
191
192 /*
193 * p->data will be printed by debug
194 */
195 path->sz = easprintf(&path->cp, "EDD10(0x%02x)", p->devnum);
196
197 if (dbg != NULL) {
198 char uuid_str[UUID_STR_LEN];
199
200 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
201 dbg->sz = easprintf(&dbg->cp,
202 DEVPATH_FMT_HDR
203 DEVPATH_FMT(GUID: %s\n)
204 DEVPATH_FMT(devnum: 0x%08x\n),
205 DEVPATH_DAT_HDR(dp),
206 uuid_str,
207 p->devnum);
208 }
209 }
210 #endif /* EFI_EDD10_PATH_GUID */
211
212 static inline void
213 devpath_hw_vendor(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
214 { /* See 10.3.2.4 */
215 struct { /* Sub-Type 4 */
216 devpath_t hdr; /* Length = 20 + n */
217 uuid_t GUID;
218 uint8_t data[];
219 } __packed *p = (void *)dp;
220 __CTASSERT(sizeof(*p) == 20);
221 char uuid_str[UUID_STR_LEN];
222
223 #ifdef EFI_EDD10_PATH_GUID
224 if (memcmp(&p->GUID, &EFI_EDD10_PATH_GUID, sizeof(uuid_t)) == 0) {
225 devpath_hw_edd10(dp, path, dbg);
226 return;
227 }
228 #endif /* EFI_EDD10_PATH_GUID */
229
230 uuid_snprintf(uuid_str, sizeof(uuid_str), &p->GUID);
231
232 /*
233 * p->data will be printed by debug
234 */
235 path->sz = easprintf(&path->cp, "VenHw(%s)", uuid_str);
236
237 if (dbg != NULL) {
238 dbg->sz = easprintf(&dbg->cp,
239 DEVPATH_FMT_HDR
240 DEVPATH_FMT(GUID: %s\n),
241 DEVPATH_DAT_HDR(dp),
242 uuid_str);
243 }
244 }
245
246 static inline void
247 devpath_hw_controller(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
248 { /* See 10.3.2.5 */
249 struct { /* Sub-Type 5 */
250 devpath_t hdr; /* Length = 8 */
251 uint32_t CtrlNum;
252 } __packed *p = (void *)dp;
253 __CTASSERT(sizeof(*p) == 8);
254
255 path->sz = easprintf(&path->cp, "Ctrl(0x%x)", p->CtrlNum);
256
257 if (dbg != NULL) {
258 dbg->sz = easprintf(&dbg->cp,
259 DEVPATH_FMT_HDR
260 DEVPATH_FMT(CtrlNum: 0x%x\n),
261 DEVPATH_DAT_HDR(dp),
262 p->CtrlNum);
263 }
264 }
265
266 static inline const char *
267 devpath_hw_bmc_iftype(uint type)
268 {
269 static const char *tbl[] = {
270 [0] = "Unknown",
271 [1] = "KCS", // Keyboard Controller Style
272 [2] = "SMIC", // Server Management Interface Chip
273 [3] = "BT", // Block Transfer
274 };
275
276 if (type >= __arraycount(tbl))
277 type = 0;
278
279 return tbl[type];
280 }
281
282 /* Baseboard Management Controller */
283 static inline void
284 devpath_hw_bmc(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
285 { /* See 10.3.2.6 */
286 struct { /* Sub-Type 6 */
287 devpath_t hdr; /* Length = 13 */
288 uint8_t IfaceType;
289 uint64_t BaseAddress;
290 } __packed *p = (void *)dp;
291 __CTASSERT(sizeof(*p) == 13);
292 const char *iftype;
293
294 iftype = devpath_hw_bmc_iftype(p->IfaceType);
295
296 path->sz = easprintf(&path->cp, "(%s,0x%016" PRIx64 ")",
297 iftype, p->BaseAddress);
298
299 if (dbg != NULL) {
300 dbg->sz = easprintf(&dbg->cp,
301 DEVPATH_FMT_HDR
302 DEVPATH_FMT(IfaceType: %u(%s)\n)
303 DEVPATH_FMT(BaseAddress:) " 0x%016" PRIx64 "\n",
304 DEVPATH_DAT_HDR(dp),
305 p->IfaceType, iftype,
306 p->BaseAddress);
307 }
308 }
309
310 PUBLIC void
311 devpath_hw(devpath_t *dp, devpath_elm_t *path, devpath_elm_t *dbg)
312 {
313
314 assert(dp->Type = 1);
315
316 switch (dp->SubType) {
317 case 1: devpath_hw_pci(dp, path, dbg); return;
318 case 2: devpath_hw_pccard(dp, path, dbg); return;
319 case 3: devpath_hw_memmap(dp, path, dbg); return;
320 case 4: devpath_hw_vendor(dp, path, dbg); return;
321 case 5: devpath_hw_controller(dp, path, dbg); return;
322 case 6: devpath_hw_bmc(dp, path, dbg); return;
323 default: devpath_unsupported(dp, path, dbg); return;
324 }
325 }
326