1*3827b167Srin /* $NetBSD: devopen.c,v 1.14 2023/06/20 07:46:03 rin Exp $ */
2d13f4989Snonaka
3d13f4989Snonaka /*-
4d13f4989Snonaka * Copyright (c) 2005 The NetBSD Foundation, Inc.
5d13f4989Snonaka * All rights reserved.
6d13f4989Snonaka *
7d13f4989Snonaka * This code is derived from software contributed to The NetBSD Foundation
8d13f4989Snonaka * by Bang Jun-Young.
9d13f4989Snonaka *
10d13f4989Snonaka * Redistribution and use in source and binary forms, with or without
11d13f4989Snonaka * modification, are permitted provided that the following conditions
12d13f4989Snonaka * are met:
13d13f4989Snonaka * 1. Redistributions of source code must retain the above copyright
14d13f4989Snonaka * notice, this list of conditions and the following disclaimer.
15d13f4989Snonaka * 2. Redistributions in binary form must reproduce the above copyright
16d13f4989Snonaka * notice, this list of conditions and the following disclaimer in the
17d13f4989Snonaka * documentation and/or other materials provided with the distribution.
18d13f4989Snonaka *
19d13f4989Snonaka * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20d13f4989Snonaka * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21d13f4989Snonaka * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22d13f4989Snonaka * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23d13f4989Snonaka * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24d13f4989Snonaka * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25d13f4989Snonaka * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26d13f4989Snonaka * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27d13f4989Snonaka * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28d13f4989Snonaka * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29d13f4989Snonaka * POSSIBILITY OF SUCH DAMAGE.
30d13f4989Snonaka */
31d13f4989Snonaka
32d13f4989Snonaka /*
33d13f4989Snonaka * Copyright (c) 1996, 1997
34d13f4989Snonaka * Matthias Drochner. All rights reserved.
35d13f4989Snonaka *
36d13f4989Snonaka * Redistribution and use in source and binary forms, with or without
37d13f4989Snonaka * modification, are permitted provided that the following conditions
38d13f4989Snonaka * are met:
39d13f4989Snonaka * 1. Redistributions of source code must retain the above copyright
40d13f4989Snonaka * notice, this list of conditions and the following disclaimer.
41d13f4989Snonaka * 2. Redistributions in binary form must reproduce the above copyright
42d13f4989Snonaka * notice, this list of conditions and the following disclaimer in the
43d13f4989Snonaka * documentation and/or other materials provided with the distribution.
44d13f4989Snonaka *
45d13f4989Snonaka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
46d13f4989Snonaka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
47d13f4989Snonaka * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
48d13f4989Snonaka * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
49d13f4989Snonaka * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
50d13f4989Snonaka * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
51d13f4989Snonaka * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
52d13f4989Snonaka * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
53d13f4989Snonaka * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
54d13f4989Snonaka * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
55d13f4989Snonaka */
56d13f4989Snonaka
57d13f4989Snonaka #include "efiboot.h"
58d13f4989Snonaka
59b014c9faSnonaka #include <lib/libsa/dev_net.h>
60fcd0bf31Snonaka #include <lib/libsa/net.h>
61b014c9faSnonaka
62d13f4989Snonaka #include <biosdisk.h>
63d13f4989Snonaka #include "devopen.h"
64d13f4989Snonaka #include <bootinfo.h>
6595e6c117Snonaka #include "efidisk.h"
66d13f4989Snonaka
67d13f4989Snonaka static int
dev2bios(char * devname,int unit,int * biosdev)68d13f4989Snonaka dev2bios(char *devname, int unit, int *biosdev)
69d13f4989Snonaka {
70d13f4989Snonaka
71d13f4989Snonaka if (strcmp(devname, "hd") == 0)
72d13f4989Snonaka *biosdev = 0x80 + unit;
737a39eefeSnonaka else if (strcmp(devname, "cd") == 0)
74cefc4c6cSnonaka *biosdev = 0x80 + get_harddrives() + unit;
75d13f4989Snonaka else
76d13f4989Snonaka return ENXIO;
77cefc4c6cSnonaka
78d13f4989Snonaka return 0;
79d13f4989Snonaka }
80d13f4989Snonaka
81d13f4989Snonaka void
bios2dev(int biosdev,daddr_t sector,char ** devname,int * unit,int * partition,const char ** part_name)8292f692b3Smanu bios2dev(int biosdev, daddr_t sector, char **devname, int *unit,
8392f692b3Smanu int *partition, const char **part_name)
84d13f4989Snonaka {
8592f692b3Smanu static char savedevname[MAXDEVNAME+1];
86d13f4989Snonaka
87d13f4989Snonaka *unit = biosdev & 0x7f;
88cefc4c6cSnonaka
89b014c9faSnonaka if (efi_bootdp_type == BOOT_DEVICE_TYPE_NET) {
90b014c9faSnonaka *devname = "net";
91b014c9faSnonaka *unit = efi_net_get_booted_interface_unit();
92b014c9faSnonaka if (*unit < 0)
93b014c9faSnonaka *unit = 0;
94b014c9faSnonaka *partition = 0;
95b014c9faSnonaka return;
96b014c9faSnonaka } else if (biosdev >= 0x80 + get_harddrives()) {
97cefc4c6cSnonaka *devname = "cd";
98cefc4c6cSnonaka *unit -= get_harddrives();
99cefc4c6cSnonaka } else
100d13f4989Snonaka *devname = "hd";
101cefc4c6cSnonaka
10292f692b3Smanu (void)biosdisk_findpartition(biosdev, sector, partition, part_name);
103214d5a7aSnonaka if (part_name != NULL && *part_name != NULL) {
1042e9b7540Smanu snprintf(savedevname, sizeof(savedevname),
1052e9b7540Smanu "NAME=%s", *part_name);
10692f692b3Smanu *devname = savedevname;
10792f692b3Smanu }
108d13f4989Snonaka }
109d13f4989Snonaka
110fcd0bf31Snonaka #if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
111fcd0bf31Snonaka const struct netboot_fstab *
netboot_fstab_find(const char * name)112fcd0bf31Snonaka netboot_fstab_find(const char *name)
113fcd0bf31Snonaka {
114fcd0bf31Snonaka int i;
115fcd0bf31Snonaka
116fcd0bf31Snonaka if (strcmp(name, "net") == 0)
117fcd0bf31Snonaka return &netboot_fstab[0];
118fcd0bf31Snonaka
119fcd0bf31Snonaka for (i = 0; i < nnetboot_fstab; i++) {
120fcd0bf31Snonaka if (strcmp(name, netboot_fstab[i].name) == 0)
121fcd0bf31Snonaka return &netboot_fstab[i];
122fcd0bf31Snonaka }
123fcd0bf31Snonaka
124fcd0bf31Snonaka return NULL;
125fcd0bf31Snonaka }
126fcd0bf31Snonaka
127fcd0bf31Snonaka static const struct netboot_fstab *
netboot_fstab_findn(const char * name,size_t len)128fcd0bf31Snonaka netboot_fstab_findn(const char *name, size_t len)
129fcd0bf31Snonaka {
130fcd0bf31Snonaka int i;
131fcd0bf31Snonaka
132fcd0bf31Snonaka if (strncmp(name, "net", len) == 0)
133fcd0bf31Snonaka return &netboot_fstab[0];
134fcd0bf31Snonaka
135fcd0bf31Snonaka for (i = 0; i < nnetboot_fstab; i++) {
136fcd0bf31Snonaka if (strncmp(name, netboot_fstab[i].name, len) == 0)
137fcd0bf31Snonaka return &netboot_fstab[i];
138fcd0bf31Snonaka }
139fcd0bf31Snonaka
140fcd0bf31Snonaka return NULL;
141fcd0bf31Snonaka }
142fcd0bf31Snonaka #endif
143fcd0bf31Snonaka
144d13f4989Snonaka struct btinfo_bootpath bibp;
145d13f4989Snonaka extern bool kernel_loaded;
146d13f4989Snonaka
147d13f4989Snonaka /*
148d13f4989Snonaka * Open the EFI disk device
149d13f4989Snonaka */
150d13f4989Snonaka int
devopen(struct open_file * f,const char * fname,char ** file)151d13f4989Snonaka devopen(struct open_file *f, const char *fname, char **file)
152d13f4989Snonaka {
153d13f4989Snonaka char *fsname, *devname;
1549d087602Smanu const char *xname = NULL;
155d13f4989Snonaka int unit, partition;
156d13f4989Snonaka int biosdev;
157*3827b167Srin int error;
158fcd0bf31Snonaka #if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
159fcd0bf31Snonaka struct devdesc desc;
160fcd0bf31Snonaka const struct netboot_fstab *nf;
161fcd0bf31Snonaka char *filename;
162fcd0bf31Snonaka size_t fsnamelen;
163*3827b167Srin int i, n;
164fcd0bf31Snonaka #endif
165d13f4989Snonaka
16695e6c117Snonaka error = parsebootfile(fname, &fsname, &devname, &unit, &partition,
16795e6c117Snonaka (const char **) file);
16895e6c117Snonaka if (error)
16995e6c117Snonaka return error;
17095e6c117Snonaka
171fcd0bf31Snonaka memcpy(file_system, file_system_disk,
172fcd0bf31Snonaka sizeof(struct fs_ops) * nfsys_disk);
173fcd0bf31Snonaka nfsys = nfsys_disk;
174fcd0bf31Snonaka
17592f692b3Smanu /* Search by GPT label or raidframe name */
1769d087602Smanu if (strstr(devname, "NAME=") == devname)
1779d087602Smanu xname = devname;
1789d087602Smanu if (strstr(devname, "raid") == devname)
1799d087602Smanu xname = fname;
1809d087602Smanu
1819d087602Smanu if (xname != NULL) {
18292f692b3Smanu f->f_dev = &devsw[0]; /* must be biosdisk */
18392f692b3Smanu
18492f692b3Smanu if (!kernel_loaded) {
18592f692b3Smanu strncpy(bibp.bootpath, *file, sizeof(bibp.bootpath));
18692f692b3Smanu BI_ADD(&bibp, BTINFO_BOOTPATH, sizeof(bibp));
18792f692b3Smanu }
18892f692b3Smanu
1899d087602Smanu error = biosdisk_open_name(f, xname);
19092f692b3Smanu return error;
19192f692b3Smanu }
19292f692b3Smanu
193fcd0bf31Snonaka /*
194fcd0bf31Snonaka * Network
195fcd0bf31Snonaka */
196b014c9faSnonaka #if defined(SUPPORT_NFS) || defined(SUPPORT_TFTP)
197fcd0bf31Snonaka nf = netboot_fstab_find(devname);
198fcd0bf31Snonaka if (nf != NULL) {
199b014c9faSnonaka n = 0;
200fcd0bf31Snonaka if (strcmp(devname, "net") == 0) {
201fcd0bf31Snonaka for (i = 0; i < nnetboot_fstab; i++) {
202fcd0bf31Snonaka memcpy(&file_system[n++], netboot_fstab[i].ops,
203fcd0bf31Snonaka sizeof(struct fs_ops));
204fcd0bf31Snonaka }
205fcd0bf31Snonaka } else {
206fcd0bf31Snonaka memcpy(&file_system[n++], nf->ops,
207fcd0bf31Snonaka sizeof(struct fs_ops));
208b014c9faSnonaka }
209b014c9faSnonaka nfsys = n;
210b014c9faSnonaka
211fcd0bf31Snonaka #ifdef SUPPORT_BOOTP
212b014c9faSnonaka try_bootp = 1;
213fcd0bf31Snonaka #endif
214fcd0bf31Snonaka
215fcd0bf31Snonaka /* If we got passed a filename, pass it to the BOOTP server. */
216fcd0bf31Snonaka if (fname) {
217fcd0bf31Snonaka filename = strchr(fname, ':');
218fcd0bf31Snonaka if (filename != NULL)
219fcd0bf31Snonaka filename++;
220fcd0bf31Snonaka else
221fcd0bf31Snonaka filename = (char *)fname;
222fcd0bf31Snonaka strlcpy(bootfile, filename, sizeof(bootfile));
223b014c9faSnonaka }
224b014c9faSnonaka
225b014c9faSnonaka memset(&desc, 0, sizeof(desc));
226fcd0bf31Snonaka strlcpy(desc.d_name, "net", sizeof(desc.d_name));
227b014c9faSnonaka desc.d_unit = unit;
228b014c9faSnonaka
229fcd0bf31Snonaka f->f_dev = &devsw[1]; /* must be net */
230b014c9faSnonaka if (!kernel_loaded) {
231fcd0bf31Snonaka strncpy(bibp.bootpath, *file, sizeof(bibp.bootpath));
232b014c9faSnonaka BI_ADD(&bibp, BTINFO_BOOTPATH, sizeof(bibp));
233b014c9faSnonaka }
234fcd0bf31Snonaka error = DEV_OPEN(f->f_dev)(f, &desc);
235fcd0bf31Snonaka if (error)
236fcd0bf31Snonaka return error;
237fcd0bf31Snonaka
238fcd0bf31Snonaka /*
239fcd0bf31Snonaka * If the DHCP server provided a file name:
240fcd0bf31Snonaka * - If it contains a ":", assume it points to a NetBSD kernel.
241fcd0bf31Snonaka * - If not, assume that the DHCP server was not able to pass
242fcd0bf31Snonaka * a separate filename for the kernel. (The name probably was
243fcd0bf31Snonaka * the same as used to load "efiboot".) Ignore it and use
244fcd0bf31Snonaka * the default in this case.
245fcd0bf31Snonaka * So we cater to simple DHCP servers while being able to use
246fcd0bf31Snonaka * the power of conditional behaviour in modern ones.
247fcd0bf31Snonaka */
248fcd0bf31Snonaka filename = strchr(bootfile, ':');
249fcd0bf31Snonaka if (filename != NULL) {
250fcd0bf31Snonaka fname = bootfile;
251fcd0bf31Snonaka
252fcd0bf31Snonaka fsnamelen = filename - fname;
253fcd0bf31Snonaka nf = netboot_fstab_findn(fname, fsnamelen);
254fcd0bf31Snonaka if (nf == NULL ||
255fcd0bf31Snonaka strncmp(fname, "net", fsnamelen) == 0) {
256fcd0bf31Snonaka printf("Invalid file system type specified in "
257fcd0bf31Snonaka "%s\n", fname);
258fcd0bf31Snonaka error = EINVAL;
259fcd0bf31Snonaka goto neterr;
260b014c9faSnonaka }
261fcd0bf31Snonaka
262fcd0bf31Snonaka memcpy(file_system, nf->ops, sizeof(struct fs_ops));
263fcd0bf31Snonaka nfsys = 1;
264b014c9faSnonaka }
265b014c9faSnonaka
266fcd0bf31Snonaka filename = fname ? strchr(fname, ':') : NULL;
267fcd0bf31Snonaka if (filename != NULL) {
268fcd0bf31Snonaka filename++;
269fcd0bf31Snonaka if (*filename == '\0') {
270fcd0bf31Snonaka printf("No file specified in %s\n", fname);
271fcd0bf31Snonaka error = EINVAL;
272fcd0bf31Snonaka goto neterr;
273fcd0bf31Snonaka }
274fcd0bf31Snonaka } else
275fcd0bf31Snonaka filename = (char *)fname;
276fcd0bf31Snonaka
277fcd0bf31Snonaka *file = filename;
278fcd0bf31Snonaka return 0;
279fcd0bf31Snonaka
280fcd0bf31Snonaka neterr:
281fcd0bf31Snonaka DEV_CLOSE(f->f_dev)(f);
282fcd0bf31Snonaka f->f_dev = NULL;
283fcd0bf31Snonaka return error;
284fcd0bf31Snonaka }
285fcd0bf31Snonaka #endif
286fcd0bf31Snonaka
287b014c9faSnonaka /*
288b014c9faSnonaka * biosdisk
289b014c9faSnonaka */
29095e6c117Snonaka if (strcmp(devname, "esp") == 0) {
29195e6c117Snonaka bios2dev(boot_biosdev, boot_biossector, &devname, &unit,
2920637ed76Ssimonb &partition, NULL);
29395e6c117Snonaka if (efidisk_get_efi_system_partition(boot_biosdev, &partition))
29495e6c117Snonaka return ENXIO;
29595e6c117Snonaka }
29695e6c117Snonaka
29795e6c117Snonaka error = dev2bios(devname, unit, &biosdev);
29895e6c117Snonaka if (error)
299d13f4989Snonaka return error;
300d13f4989Snonaka
301d13f4989Snonaka f->f_dev = &devsw[0]; /* must be biosdisk */
302d13f4989Snonaka
303d13f4989Snonaka if (!kernel_loaded) {
304d13f4989Snonaka strncpy(bibp.bootpath, *file, sizeof(bibp.bootpath));
305d13f4989Snonaka BI_ADD(&bibp, BTINFO_BOOTPATH, sizeof(bibp));
306d13f4989Snonaka }
307d13f4989Snonaka
308d13f4989Snonaka return biosdisk_open(f, biosdev, partition);
309d13f4989Snonaka }
310