efidisk.c revision 1.10 1 1.10 riastrad /* $NetBSD: efidisk.c,v 1.10 2023/05/14 09:07:54 riastradh Exp $ */
2 1.1 nonaka
3 1.1 nonaka /*-
4 1.1 nonaka * Copyright (c) 2016 Kimihiro Nonaka <nonaka (at) netbsd.org>
5 1.1 nonaka * All rights reserved.
6 1.1 nonaka *
7 1.1 nonaka * Redistribution and use in source and binary forms, with or without
8 1.1 nonaka * modification, are permitted provided that the following conditions
9 1.1 nonaka * are met:
10 1.1 nonaka * 1. Redistributions of source code must retain the above copyright
11 1.1 nonaka * notice, this list of conditions and the following disclaimer.
12 1.1 nonaka * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 nonaka * notice, this list of conditions and the following disclaimer in the
14 1.1 nonaka * documentation and/or other materials provided with the distribution.
15 1.1 nonaka *
16 1.1 nonaka * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
17 1.1 nonaka * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 1.1 nonaka * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 1.1 nonaka * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
20 1.1 nonaka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 1.1 nonaka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 1.1 nonaka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 1.1 nonaka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 1.1 nonaka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 1.1 nonaka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 1.1 nonaka * SUCH DAMAGE.
27 1.1 nonaka */
28 1.1 nonaka
29 1.2 nonaka #define FSTYPENAMES /* for sys/disklabel.h */
30 1.2 nonaka
31 1.1 nonaka #include "efiboot.h"
32 1.1 nonaka
33 1.8 manu #include <sys/param.h> /* for howmany, required by <dev/raidframe/raidframevar.h> */
34 1.2 nonaka #include <sys/disklabel.h>
35 1.8 manu #include <sys/disklabel_gpt.h>
36 1.2 nonaka
37 1.2 nonaka #include "biosdisk.h"
38 1.2 nonaka #include "biosdisk_ll.h"
39 1.2 nonaka #include "devopen.h"
40 1.1 nonaka #include "efidisk.h"
41 1.1 nonaka
42 1.1 nonaka static struct efidiskinfo_lh efi_disklist;
43 1.1 nonaka static int nefidisks;
44 1.1 nonaka
45 1.8 manu #define MAXDEVNAME 39 /* "NAME=" + 34 char part_name */
46 1.8 manu
47 1.8 manu #include <dev/raidframe/raidframevar.h>
48 1.8 manu #define RF_COMPONENT_INFO_OFFSET 16384 /* from sys/dev/raidframe/rf_netbsdkintf.c */
49 1.8 manu #define RF_COMPONENT_LABEL_VERSION 2 /* from <dev/raidframe/rf_raid.h> */
50 1.8 manu
51 1.8 manu #define RAIDFRAME_NDEV 16 /* abitrary limit to 15 raidframe devices */
52 1.8 manu struct efi_raidframe {
53 1.8 manu int last_unit;
54 1.8 manu int serial;
55 1.8 manu const struct efidiskinfo *edi;
56 1.8 manu int parent_part;
57 1.8 manu char parent_name[MAXDEVNAME + 1];
58 1.8 manu daddr_t offset;
59 1.8 manu daddr_t size;
60 1.8 manu };
61 1.8 manu
62 1.8 manu static void
63 1.8 manu dealloc_biosdisk_part(struct biosdisk_partition *part, int nparts)
64 1.8 manu {
65 1.8 manu int i;
66 1.8 manu
67 1.8 manu for (i = 0; i < nparts; i++) {
68 1.8 manu if (part[i].part_name != NULL) {
69 1.8 manu dealloc(part[i].part_name, BIOSDISK_PART_NAME_LEN);
70 1.8 manu part[i].part_name = NULL;
71 1.8 manu }
72 1.8 manu }
73 1.10 riastrad
74 1.8 manu dealloc(part, sizeof(*part) * nparts);
75 1.10 riastrad
76 1.8 manu return;
77 1.8 manu }
78 1.8 manu
79 1.1 nonaka void
80 1.1 nonaka efi_disk_probe(void)
81 1.1 nonaka {
82 1.1 nonaka EFI_STATUS status;
83 1.1 nonaka UINTN i, nhandles;
84 1.1 nonaka EFI_HANDLE *handles;
85 1.1 nonaka EFI_BLOCK_IO *bio;
86 1.1 nonaka EFI_BLOCK_IO_MEDIA *media;
87 1.2 nonaka EFI_DEVICE_PATH *dp;
88 1.1 nonaka struct efidiskinfo *edi;
89 1.2 nonaka int dev, depth = -1;
90 1.1 nonaka
91 1.1 nonaka TAILQ_INIT(&efi_disklist);
92 1.1 nonaka
93 1.1 nonaka status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL,
94 1.1 nonaka &nhandles, &handles);
95 1.1 nonaka if (EFI_ERROR(status))
96 1.7 nonaka return;
97 1.1 nonaka
98 1.2 nonaka if (efi_bootdp != NULL)
99 1.2 nonaka depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
100 1.2 nonaka
101 1.2 nonaka /*
102 1.2 nonaka * U-Boot incorrectly represents devices with a single
103 1.2 nonaka * MEDIA_DEVICE_PATH component. In that case include that
104 1.2 nonaka * component into the matching, otherwise we'll blindly select
105 1.2 nonaka * the first device.
106 1.2 nonaka */
107 1.2 nonaka if (depth == 0)
108 1.2 nonaka depth = 1;
109 1.2 nonaka
110 1.1 nonaka for (i = 0; i < nhandles; i++) {
111 1.1 nonaka status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
112 1.1 nonaka &BlockIoProtocol, (void **)&bio);
113 1.1 nonaka if (EFI_ERROR(status))
114 1.7 nonaka continue;
115 1.1 nonaka
116 1.1 nonaka media = bio->Media;
117 1.1 nonaka if (media->LogicalPartition || !media->MediaPresent)
118 1.1 nonaka continue;
119 1.1 nonaka
120 1.1 nonaka edi = alloc(sizeof(struct efidiskinfo));
121 1.1 nonaka memset(edi, 0, sizeof(*edi));
122 1.2 nonaka edi->type = BIOSDISK_TYPE_HD;
123 1.1 nonaka edi->bio = bio;
124 1.1 nonaka edi->media_id = media->MediaId;
125 1.1 nonaka
126 1.2 nonaka if (efi_bootdp != NULL && depth > 0) {
127 1.2 nonaka status = uefi_call_wrapper(BS->HandleProtocol, 3,
128 1.2 nonaka handles[i], &DevicePathProtocol, (void **)&dp);
129 1.2 nonaka if (EFI_ERROR(status))
130 1.2 nonaka goto next;
131 1.2 nonaka if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
132 1.2 nonaka edi->bootdev = true;
133 1.2 nonaka TAILQ_INSERT_HEAD(&efi_disklist, edi,
134 1.2 nonaka list);
135 1.2 nonaka continue;
136 1.2 nonaka }
137 1.2 nonaka }
138 1.2 nonaka next:
139 1.2 nonaka TAILQ_INSERT_TAIL(&efi_disklist, edi, list);
140 1.2 nonaka }
141 1.1 nonaka
142 1.2 nonaka FreePool(handles);
143 1.1 nonaka
144 1.6 nonaka if (efi_bootdp_type == BOOT_DEVICE_TYPE_CD) {
145 1.3 nonaka edi = TAILQ_FIRST(&efi_disklist);
146 1.3 nonaka if (edi != NULL && edi->bootdev) {
147 1.3 nonaka edi->type = BIOSDISK_TYPE_CD;
148 1.3 nonaka TAILQ_REMOVE(&efi_disklist, edi, list);
149 1.3 nonaka TAILQ_INSERT_TAIL(&efi_disklist, edi, list);
150 1.1 nonaka }
151 1.1 nonaka }
152 1.1 nonaka
153 1.1 nonaka dev = 0x80;
154 1.1 nonaka TAILQ_FOREACH(edi, &efi_disklist, list) {
155 1.1 nonaka edi->dev = dev++;
156 1.2 nonaka if (edi->type == BIOSDISK_TYPE_HD)
157 1.2 nonaka nefidisks++;
158 1.2 nonaka if (edi->bootdev)
159 1.2 nonaka boot_biosdev = edi->dev;
160 1.2 nonaka }
161 1.2 nonaka }
162 1.2 nonaka
163 1.8 manu static void
164 1.8 manu efi_raidframe_probe(struct efi_raidframe *raidframe, int *raidframe_count,
165 1.8 manu const struct efidiskinfo *edi,
166 1.8 manu struct biosdisk_partition *part, int parent_part)
167 1.8 manu
168 1.8 manu {
169 1.8 manu int i = *raidframe_count;
170 1.8 manu struct RF_ComponentLabel_s label;
171 1.8 manu
172 1.8 manu if (i + 1 > RAIDFRAME_NDEV)
173 1.8 manu return;
174 1.8 manu
175 1.8 manu if (biosdisk_read_raidframe(edi->dev, part->offset, &label) != 0)
176 1.8 manu return;
177 1.8 manu
178 1.8 manu if (label.version != RF_COMPONENT_LABEL_VERSION)
179 1.8 manu return;
180 1.8 manu
181 1.8 manu raidframe[i].last_unit = label.last_unit;
182 1.8 manu raidframe[i].serial = label.serial_number;
183 1.8 manu raidframe[i].edi = edi;
184 1.8 manu raidframe[i].parent_part = parent_part;
185 1.8 manu if (part->part_name)
186 1.8 manu strlcpy(raidframe[i].parent_name, part->part_name, MAXDEVNAME);
187 1.8 manu else
188 1.8 manu raidframe[i].parent_name[0] = '\0';
189 1.8 manu raidframe[i].offset = part->offset;
190 1.8 manu raidframe[i].size = label.__numBlocks;
191 1.8 manu
192 1.8 manu (*raidframe_count)++;
193 1.8 manu
194 1.8 manu return;
195 1.8 manu }
196 1.8 manu
197 1.2 nonaka void
198 1.2 nonaka efi_disk_show(void)
199 1.2 nonaka {
200 1.2 nonaka const struct efidiskinfo *edi;
201 1.8 manu struct efi_raidframe raidframe[RAIDFRAME_NDEV];
202 1.8 manu int raidframe_count = 0;
203 1.2 nonaka EFI_BLOCK_IO_MEDIA *media;
204 1.2 nonaka struct biosdisk_partition *part;
205 1.2 nonaka uint64_t size;
206 1.8 manu int i, j, nparts;
207 1.2 nonaka bool first;
208 1.2 nonaka
209 1.2 nonaka TAILQ_FOREACH(edi, &efi_disklist, list) {
210 1.2 nonaka media = edi->bio->Media;
211 1.2 nonaka first = true;
212 1.2 nonaka printf("disk ");
213 1.2 nonaka switch (edi->type) {
214 1.2 nonaka case BIOSDISK_TYPE_CD:
215 1.2 nonaka printf("cd0");
216 1.2 nonaka printf(" mediaId %u", media->MediaId);
217 1.2 nonaka if (edi->media_id != media->MediaId)
218 1.2 nonaka printf("(%u)", edi->media_id);
219 1.2 nonaka printf("\n");
220 1.2 nonaka printf(" cd0a\n");
221 1.2 nonaka break;
222 1.2 nonaka case BIOSDISK_TYPE_HD:
223 1.2 nonaka printf("hd%d", edi->dev & 0x7f);
224 1.2 nonaka printf(" mediaId %u", media->MediaId);
225 1.2 nonaka if (edi->media_id != media->MediaId)
226 1.2 nonaka printf("(%u)", edi->media_id);
227 1.2 nonaka printf(" size ");
228 1.2 nonaka size = (media->LastBlock + 1) * media->BlockSize;
229 1.2 nonaka if (size >= (10ULL * 1024 * 1024 * 1024))
230 1.2 nonaka printf("%"PRIu64" GB", size / (1024 * 1024 * 1024));
231 1.2 nonaka else
232 1.2 nonaka printf("%"PRIu64" MB", size / (1024 * 1024));
233 1.2 nonaka printf("\n");
234 1.2 nonaka break;
235 1.2 nonaka }
236 1.2 nonaka if (edi->type != BIOSDISK_TYPE_HD)
237 1.2 nonaka continue;
238 1.2 nonaka
239 1.8 manu if (biosdisk_readpartition(edi->dev, 0, 0, &part, &nparts))
240 1.2 nonaka continue;
241 1.2 nonaka
242 1.2 nonaka for (i = 0; i < nparts; i++) {
243 1.2 nonaka if (part[i].size == 0)
244 1.2 nonaka continue;
245 1.2 nonaka if (part[i].fstype == FS_UNUSED)
246 1.2 nonaka continue;
247 1.8 manu if (part[i].fstype == FS_RAID) {
248 1.8 manu efi_raidframe_probe(raidframe, &raidframe_count,
249 1.8 manu edi, &part[i], i);
250 1.8 manu }
251 1.2 nonaka if (first) {
252 1.2 nonaka printf(" ");
253 1.2 nonaka first = false;
254 1.2 nonaka }
255 1.9 manu if (part[i].part_name && part[i].part_name[0])
256 1.8 manu printf(" NAME=%s(", part[i].part_name);
257 1.8 manu else
258 1.8 manu printf(" hd%d%c(", edi->dev & 0x7f, i + 'a');
259 1.2 nonaka if (part[i].guid != NULL)
260 1.2 nonaka printf("%s", part[i].guid->name);
261 1.2 nonaka else if (part[i].fstype < FSMAXTYPES)
262 1.2 nonaka printf("%s", fstypenames[part[i].fstype]);
263 1.2 nonaka else
264 1.2 nonaka printf("%d", part[i].fstype);
265 1.2 nonaka printf(")");
266 1.2 nonaka }
267 1.2 nonaka if (!first)
268 1.2 nonaka printf("\n");
269 1.8 manu dealloc_biosdisk_part(part, nparts);
270 1.8 manu }
271 1.8 manu
272 1.8 manu for (i = 0; i < raidframe_count; i++) {
273 1.8 manu size_t secsize = raidframe[i].edi->bio->Media->BlockSize;
274 1.8 manu printf("raidframe raid%d serial %d in ",
275 1.8 manu raidframe[i].last_unit, raidframe[i].serial);
276 1.8 manu if (raidframe[i].parent_name[0])
277 1.8 manu printf("NAME=%s size ", raidframe[i].parent_name);
278 1.8 manu else
279 1.8 manu printf("hd%d%c size ",
280 1.8 manu raidframe[i].edi->dev & 0x7f,
281 1.8 manu raidframe[i].parent_part + 'a');
282 1.8 manu if (raidframe[i].size >= (10ULL * 1024 * 1024 * 1024 / secsize))
283 1.8 manu printf("%"PRIu64" GB",
284 1.8 manu raidframe[i].size / (1024 * 1024 * 1024 / secsize));
285 1.8 manu else
286 1.8 manu printf("%"PRIu64" MB",
287 1.8 manu raidframe[i].size / (1024 * 1024 / secsize));
288 1.8 manu printf("\n");
289 1.8 manu
290 1.8 manu if (biosdisk_readpartition(raidframe[i].edi->dev,
291 1.8 manu raidframe[i].offset + RF_PROTECTED_SECTORS,
292 1.8 manu raidframe[i].size,
293 1.8 manu &part, &nparts))
294 1.8 manu continue;
295 1.10 riastrad
296 1.8 manu first = 1;
297 1.8 manu for (j = 0; j < nparts; j++) {
298 1.8 manu bool bootme = part[j].attr & GPT_ENT_ATTR_BOOTME;
299 1.8 manu
300 1.8 manu if (part[j].size == 0)
301 1.8 manu continue;
302 1.8 manu if (part[j].fstype == FS_UNUSED)
303 1.8 manu continue;
304 1.8 manu if (part[j].fstype == FS_RAID) /* raid in raid? */
305 1.8 manu continue;
306 1.8 manu if (first) {
307 1.8 manu printf(" ");
308 1.8 manu first = 0;
309 1.8 manu }
310 1.9 manu if (part[j].part_name && part[j].part_name[0])
311 1.8 manu printf(" NAME=%s(", part[j].part_name);
312 1.8 manu else
313 1.8 manu printf(" raid%d%c(",
314 1.8 manu raidframe[i].last_unit, j + 'a');
315 1.8 manu if (part[j].guid != NULL)
316 1.8 manu printf("%s", part[j].guid->name);
317 1.8 manu else if (part[j].fstype < FSMAXTYPES)
318 1.8 manu printf("%s",
319 1.8 manu fstypenames[part[j].fstype]);
320 1.8 manu else
321 1.8 manu printf("%d", part[j].fstype);
322 1.8 manu printf("%s)", bootme ? ", bootme" : "");
323 1.8 manu }
324 1.8 manu
325 1.8 manu if (first == 0)
326 1.8 manu printf("\n");
327 1.8 manu
328 1.8 manu dealloc_biosdisk_part(part, nparts);
329 1.1 nonaka }
330 1.1 nonaka }
331 1.1 nonaka
332 1.1 nonaka const struct efidiskinfo *
333 1.1 nonaka efidisk_getinfo(int dev)
334 1.1 nonaka {
335 1.1 nonaka const struct efidiskinfo *edi;
336 1.1 nonaka
337 1.1 nonaka TAILQ_FOREACH(edi, &efi_disklist, list) {
338 1.1 nonaka if (dev == edi->dev)
339 1.1 nonaka return edi;
340 1.1 nonaka }
341 1.1 nonaka return NULL;
342 1.1 nonaka }
343 1.1 nonaka
344 1.1 nonaka /*
345 1.1 nonaka * Return the number of hard disk drives.
346 1.1 nonaka */
347 1.1 nonaka int
348 1.1 nonaka get_harddrives(void)
349 1.1 nonaka {
350 1.1 nonaka return nefidisks;
351 1.1 nonaka }
352 1.5 nonaka
353 1.5 nonaka int
354 1.5 nonaka efidisk_get_efi_system_partition(int dev, int *partition)
355 1.5 nonaka {
356 1.5 nonaka extern const struct uuid GET_efi;
357 1.5 nonaka const struct efidiskinfo *edi;
358 1.5 nonaka struct biosdisk_partition *part;
359 1.5 nonaka int i, nparts;
360 1.5 nonaka
361 1.5 nonaka edi = efidisk_getinfo(dev);
362 1.5 nonaka if (edi == NULL)
363 1.5 nonaka return ENXIO;
364 1.5 nonaka
365 1.5 nonaka if (edi->type != BIOSDISK_TYPE_HD)
366 1.5 nonaka return ENOTSUP;
367 1.5 nonaka
368 1.8 manu if (biosdisk_readpartition(edi->dev, 0, 0, &part, &nparts))
369 1.5 nonaka return EIO;
370 1.5 nonaka
371 1.5 nonaka for (i = 0; i < nparts; i++) {
372 1.5 nonaka if (part[i].size == 0)
373 1.5 nonaka continue;
374 1.5 nonaka if (part[i].fstype == FS_UNUSED)
375 1.5 nonaka continue;
376 1.5 nonaka if (guid_is_equal(part[i].guid->guid, &GET_efi))
377 1.5 nonaka break;
378 1.5 nonaka }
379 1.8 manu dealloc_biosdisk_part(part, nparts);
380 1.5 nonaka if (i == nparts)
381 1.5 nonaka return ENOENT;
382 1.5 nonaka
383 1.5 nonaka *partition = i;
384 1.5 nonaka return 0;
385 1.5 nonaka }
386