1 /* $NetBSD: autoconf.c,v 1.11 2023/12/20 15:00:08 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 2002 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26 * POSSIBILITY OF SUCH DAMAGE.
27 */
28
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.11 2023/12/20 15:00:08 thorpej Exp $");
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/device.h>
35 #include <sys/disklabel.h>
36 #include <sys/conf.h>
37 #include <sys/vnode.h>
38 #include <sys/fcntl.h>
39 #include <sys/disk.h>
40 #include <sys/proc.h>
41 #include <sys/kauth.h>
42
43 #include <machine/bootinfo.h>
44 #include <machine/intr.h>
45
46 void
cpu_configure(void)47 cpu_configure(void)
48 {
49
50 /* Start configuration */
51 splhigh();
52 intr_init();
53
54 if (config_rootfound("mainbus", NULL) == NULL)
55 panic("no mainbus found");
56
57 /* Configuration is finished, turn on interrupts. */
58 spl0();
59 }
60
61 static int
is_valid_disk(device_t dv)62 is_valid_disk(device_t dv)
63 {
64 const char *name;
65
66 if (device_class(dv) != DV_DISK)
67 return (0);
68
69 name = device_cfdata(dv)->cf_name;
70
71 return (strcmp(name, "sd") == 0 || strcmp(name, "wd") == 0 ||
72 strcmp(name, "ld") == 0);
73 }
74
75 /*
76 * Helper function for findroot():
77 * Return non-zero if disk device matches bootinfo.
78 */
79 static int
match_bootdisk(device_t dv,struct btinfo_bootdisk * bid)80 match_bootdisk(device_t dv, struct btinfo_bootdisk *bid)
81 {
82 struct vnode *tmpvn;
83 int error;
84 struct disklabel label;
85 int found = 0;
86 int bmajor;
87
88 /*
89 * A disklabel is required here. The boot loader doesn't refuse
90 * to boot from a disk without a label, but this is normally not
91 * wanted.
92 */
93 if (bid->labelsector == -1)
94 return (0);
95
96 /*
97 * Lookup major number for disk block device.
98 */
99 bmajor = devsw_name2blk(device_xname(dv), NULL, 0);
100 if (bmajor == -1)
101 return (0); /* XXX panic ??? */
102
103 /*
104 * Fake a temporary vnode for the disk, open it, and read
105 * the disklabel for comparison.
106 */
107 if (bdevvp(MAKEDISKDEV(bmajor, device_unit(dv), RAW_PART), &tmpvn))
108 panic("match_bootdisk: can't alloc vnode");
109 vn_lock(tmpvn, LK_EXCLUSIVE | LK_RETRY);
110 error = VOP_OPEN(tmpvn, FREAD, NOCRED);
111 if (error) {
112 #ifndef DEBUG
113 /*
114 * Ignore errors caused by missing device, partition,
115 * or medium.
116 */
117 if (error != ENXIO && error != ENODEV)
118 #endif
119 aprint_error("match_bootdisk: can't open dev %s (%d)\n",
120 device_xname(dv), error);
121 vput(tmpvn);
122 return (0);
123 }
124 VOP_UNLOCK(tmpvn);
125 error = VOP_IOCTL(tmpvn, DIOCGDINFO, &label, FREAD, NOCRED);
126 if (error) {
127 /*
128 * XXX Can't happen -- open() would have errored out
129 * or faked one up.
130 */
131 aprint_error("match_bootdisk: can't get label for dev %s (%d)\n",
132 device_xname(dv), error);
133 goto closeout;
134 }
135
136 /* Compare with our data. */
137 if (label.d_type == bid->label.type &&
138 label.d_checksum == bid->label.checksum &&
139 strncmp(label.d_packname, bid->label.packname, 16) == 0)
140 found = 1;
141
142 closeout:
143 vn_lock(tmpvn, LK_EXCLUSIVE | LK_RETRY);
144 VOP_CLOSE(tmpvn, FREAD, NOCRED);
145 vput(tmpvn);
146 return (found);
147 }
148
149 /*
150 * Attempt to find the device from which we were booted. If we can do so,
151 * and not instructed not to do so, change rootdev to correspond to the
152 * load device.
153 */
154 static void
findroot(void)155 findroot(void)
156 {
157 struct btinfo_bootdisk *bid;
158 device_t dv;
159 deviter_t di;
160
161 if (booted_device)
162 return;
163
164 if ((bid = lookup_bootinfo(BTINFO_BOOTDISK)) != NULL) {
165 /*
166 * Scan all disk devices for ones that match the passed data.
167 * Don't break if one is found, to get possible multiple
168 * matches - for problem tracking. Use the first match anyway
169 * because lower device numbers are more likely to be the
170 * boot device.
171 */
172 for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST);
173 dv != NULL;
174 dv = deviter_next(&di)) {
175 if (device_class(dv) != DV_DISK)
176 continue;
177
178 if (is_valid_disk(dv)) {
179 if (match_bootdisk(dv, bid) == 0)
180 continue;
181 goto bootdisk_found;
182 }
183 continue;
184
185 bootdisk_found:
186 if (booted_device) {
187 aprint_error("WARNING: double match for boot "
188 "device (%s, %s)\n",
189 device_xname(booted_device), device_xname(dv));
190 continue;
191 }
192 booted_device = dv;
193 booted_partition = bid->partition;
194 }
195 deviter_release(&di);
196
197 if (booted_device)
198 return;
199 }
200 }
201
202 void
cpu_rootconf(void)203 cpu_rootconf(void)
204 {
205
206 findroot();
207
208 aprint_normal("boot device: %s\n",
209 booted_device ? device_xname(booted_device) : "<unknown>");
210 rootconf();
211 }
212