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