efidisk.c revision 1.7 1 1.7 nonaka /* $NetBSD: efidisk.c,v 1.7 2019/04/17 06:50:34 nonaka 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.2 nonaka #include <sys/disklabel.h>
34 1.2 nonaka
35 1.2 nonaka #include "biosdisk.h"
36 1.2 nonaka #include "biosdisk_ll.h"
37 1.2 nonaka #include "devopen.h"
38 1.1 nonaka #include "efidisk.h"
39 1.1 nonaka
40 1.1 nonaka static struct efidiskinfo_lh efi_disklist;
41 1.1 nonaka static int nefidisks;
42 1.1 nonaka
43 1.1 nonaka void
44 1.1 nonaka efi_disk_probe(void)
45 1.1 nonaka {
46 1.1 nonaka EFI_STATUS status;
47 1.1 nonaka UINTN i, nhandles;
48 1.1 nonaka EFI_HANDLE *handles;
49 1.1 nonaka EFI_BLOCK_IO *bio;
50 1.1 nonaka EFI_BLOCK_IO_MEDIA *media;
51 1.2 nonaka EFI_DEVICE_PATH *dp;
52 1.1 nonaka struct efidiskinfo *edi;
53 1.2 nonaka int dev, depth = -1;
54 1.1 nonaka
55 1.1 nonaka TAILQ_INIT(&efi_disklist);
56 1.1 nonaka
57 1.1 nonaka status = LibLocateHandle(ByProtocol, &BlockIoProtocol, NULL,
58 1.1 nonaka &nhandles, &handles);
59 1.1 nonaka if (EFI_ERROR(status))
60 1.7 nonaka return;
61 1.1 nonaka
62 1.2 nonaka if (efi_bootdp != NULL)
63 1.2 nonaka depth = efi_device_path_depth(efi_bootdp, MEDIA_DEVICE_PATH);
64 1.2 nonaka
65 1.2 nonaka /*
66 1.2 nonaka * U-Boot incorrectly represents devices with a single
67 1.2 nonaka * MEDIA_DEVICE_PATH component. In that case include that
68 1.2 nonaka * component into the matching, otherwise we'll blindly select
69 1.2 nonaka * the first device.
70 1.2 nonaka */
71 1.2 nonaka if (depth == 0)
72 1.2 nonaka depth = 1;
73 1.2 nonaka
74 1.1 nonaka for (i = 0; i < nhandles; i++) {
75 1.1 nonaka status = uefi_call_wrapper(BS->HandleProtocol, 3, handles[i],
76 1.1 nonaka &BlockIoProtocol, (void **)&bio);
77 1.1 nonaka if (EFI_ERROR(status))
78 1.7 nonaka continue;
79 1.1 nonaka
80 1.1 nonaka media = bio->Media;
81 1.1 nonaka if (media->LogicalPartition || !media->MediaPresent)
82 1.1 nonaka continue;
83 1.1 nonaka
84 1.1 nonaka edi = alloc(sizeof(struct efidiskinfo));
85 1.1 nonaka memset(edi, 0, sizeof(*edi));
86 1.2 nonaka edi->type = BIOSDISK_TYPE_HD;
87 1.1 nonaka edi->bio = bio;
88 1.1 nonaka edi->media_id = media->MediaId;
89 1.1 nonaka
90 1.2 nonaka if (efi_bootdp != NULL && depth > 0) {
91 1.2 nonaka status = uefi_call_wrapper(BS->HandleProtocol, 3,
92 1.2 nonaka handles[i], &DevicePathProtocol, (void **)&dp);
93 1.2 nonaka if (EFI_ERROR(status))
94 1.2 nonaka goto next;
95 1.2 nonaka if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
96 1.2 nonaka edi->bootdev = true;
97 1.2 nonaka TAILQ_INSERT_HEAD(&efi_disklist, edi,
98 1.2 nonaka list);
99 1.2 nonaka continue;
100 1.2 nonaka }
101 1.2 nonaka }
102 1.2 nonaka next:
103 1.2 nonaka TAILQ_INSERT_TAIL(&efi_disklist, edi, list);
104 1.2 nonaka }
105 1.1 nonaka
106 1.2 nonaka FreePool(handles);
107 1.1 nonaka
108 1.6 nonaka if (efi_bootdp_type == BOOT_DEVICE_TYPE_CD) {
109 1.3 nonaka edi = TAILQ_FIRST(&efi_disklist);
110 1.3 nonaka if (edi != NULL && edi->bootdev) {
111 1.3 nonaka edi->type = BIOSDISK_TYPE_CD;
112 1.3 nonaka TAILQ_REMOVE(&efi_disklist, edi, list);
113 1.3 nonaka TAILQ_INSERT_TAIL(&efi_disklist, edi, list);
114 1.1 nonaka }
115 1.1 nonaka }
116 1.1 nonaka
117 1.1 nonaka dev = 0x80;
118 1.1 nonaka TAILQ_FOREACH(edi, &efi_disklist, list) {
119 1.1 nonaka edi->dev = dev++;
120 1.2 nonaka if (edi->type == BIOSDISK_TYPE_HD)
121 1.2 nonaka nefidisks++;
122 1.2 nonaka if (edi->bootdev)
123 1.2 nonaka boot_biosdev = edi->dev;
124 1.2 nonaka }
125 1.2 nonaka }
126 1.2 nonaka
127 1.2 nonaka void
128 1.2 nonaka efi_disk_show(void)
129 1.2 nonaka {
130 1.2 nonaka const struct efidiskinfo *edi;
131 1.2 nonaka EFI_BLOCK_IO_MEDIA *media;
132 1.2 nonaka struct biosdisk_partition *part;
133 1.2 nonaka uint64_t size;
134 1.2 nonaka int i, nparts;
135 1.2 nonaka bool first;
136 1.2 nonaka
137 1.2 nonaka TAILQ_FOREACH(edi, &efi_disklist, list) {
138 1.2 nonaka media = edi->bio->Media;
139 1.2 nonaka first = true;
140 1.2 nonaka printf("disk ");
141 1.2 nonaka switch (edi->type) {
142 1.2 nonaka case BIOSDISK_TYPE_CD:
143 1.2 nonaka printf("cd0");
144 1.2 nonaka printf(" mediaId %u", media->MediaId);
145 1.2 nonaka if (edi->media_id != media->MediaId)
146 1.2 nonaka printf("(%u)", edi->media_id);
147 1.2 nonaka printf("\n");
148 1.2 nonaka printf(" cd0a\n");
149 1.2 nonaka break;
150 1.2 nonaka case BIOSDISK_TYPE_HD:
151 1.2 nonaka printf("hd%d", edi->dev & 0x7f);
152 1.2 nonaka printf(" mediaId %u", media->MediaId);
153 1.2 nonaka if (edi->media_id != media->MediaId)
154 1.2 nonaka printf("(%u)", edi->media_id);
155 1.2 nonaka printf(" size ");
156 1.2 nonaka size = (media->LastBlock + 1) * media->BlockSize;
157 1.2 nonaka if (size >= (10ULL * 1024 * 1024 * 1024))
158 1.2 nonaka printf("%"PRIu64" GB", size / (1024 * 1024 * 1024));
159 1.2 nonaka else
160 1.2 nonaka printf("%"PRIu64" MB", size / (1024 * 1024));
161 1.2 nonaka printf("\n");
162 1.2 nonaka break;
163 1.2 nonaka }
164 1.2 nonaka if (edi->type != BIOSDISK_TYPE_HD)
165 1.2 nonaka continue;
166 1.2 nonaka
167 1.2 nonaka if (biosdisk_readpartition(edi->dev, &part, &nparts))
168 1.2 nonaka continue;
169 1.2 nonaka
170 1.2 nonaka for (i = 0; i < nparts; i++) {
171 1.2 nonaka if (part[i].size == 0)
172 1.2 nonaka continue;
173 1.2 nonaka if (part[i].fstype == FS_UNUSED)
174 1.2 nonaka continue;
175 1.2 nonaka if (first) {
176 1.2 nonaka printf(" ");
177 1.2 nonaka first = false;
178 1.2 nonaka }
179 1.2 nonaka printf(" hd%d%c(", edi->dev & 0x7f, i + 'a');
180 1.2 nonaka if (part[i].guid != NULL)
181 1.2 nonaka printf("%s", part[i].guid->name);
182 1.2 nonaka else if (part[i].fstype < FSMAXTYPES)
183 1.2 nonaka printf("%s", fstypenames[part[i].fstype]);
184 1.2 nonaka else
185 1.2 nonaka printf("%d", part[i].fstype);
186 1.2 nonaka printf(")");
187 1.2 nonaka }
188 1.2 nonaka if (!first)
189 1.2 nonaka printf("\n");
190 1.2 nonaka dealloc(part, sizeof(*part) * nparts);
191 1.1 nonaka }
192 1.1 nonaka }
193 1.1 nonaka
194 1.1 nonaka const struct efidiskinfo *
195 1.1 nonaka efidisk_getinfo(int dev)
196 1.1 nonaka {
197 1.1 nonaka const struct efidiskinfo *edi;
198 1.1 nonaka
199 1.1 nonaka TAILQ_FOREACH(edi, &efi_disklist, list) {
200 1.1 nonaka if (dev == edi->dev)
201 1.1 nonaka return edi;
202 1.1 nonaka }
203 1.1 nonaka return NULL;
204 1.1 nonaka }
205 1.1 nonaka
206 1.1 nonaka /*
207 1.1 nonaka * Return the number of hard disk drives.
208 1.1 nonaka */
209 1.1 nonaka int
210 1.1 nonaka get_harddrives(void)
211 1.1 nonaka {
212 1.1 nonaka return nefidisks;
213 1.1 nonaka }
214 1.5 nonaka
215 1.5 nonaka int
216 1.5 nonaka efidisk_get_efi_system_partition(int dev, int *partition)
217 1.5 nonaka {
218 1.5 nonaka extern const struct uuid GET_efi;
219 1.5 nonaka const struct efidiskinfo *edi;
220 1.5 nonaka struct biosdisk_partition *part;
221 1.5 nonaka int i, nparts;
222 1.5 nonaka
223 1.5 nonaka edi = efidisk_getinfo(dev);
224 1.5 nonaka if (edi == NULL)
225 1.5 nonaka return ENXIO;
226 1.5 nonaka
227 1.5 nonaka if (edi->type != BIOSDISK_TYPE_HD)
228 1.5 nonaka return ENOTSUP;
229 1.5 nonaka
230 1.5 nonaka if (biosdisk_readpartition(edi->dev, &part, &nparts))
231 1.5 nonaka return EIO;
232 1.5 nonaka
233 1.5 nonaka for (i = 0; i < nparts; i++) {
234 1.5 nonaka if (part[i].size == 0)
235 1.5 nonaka continue;
236 1.5 nonaka if (part[i].fstype == FS_UNUSED)
237 1.5 nonaka continue;
238 1.5 nonaka if (guid_is_equal(part[i].guid->guid, &GET_efi))
239 1.5 nonaka break;
240 1.5 nonaka }
241 1.5 nonaka dealloc(part, sizeof(*part) * nparts);
242 1.5 nonaka if (i == nparts)
243 1.5 nonaka return ENOENT;
244 1.5 nonaka
245 1.5 nonaka *partition = i;
246 1.5 nonaka return 0;
247 1.5 nonaka }
248