1 /* $NetBSD: autoconf.c,v 1.9 2009/11/05 18:17:34 dyoung 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.9 2009/11/05 18:17:34 dyoung Exp $"); 31 32 #include "opt_md.h" 33 34 #include <sys/param.h> 35 #include <sys/systm.h> 36 #include <sys/device.h> 37 #include <sys/disklabel.h> 38 #include <sys/conf.h> 39 #include <sys/malloc.h> 40 #include <sys/vnode.h> 41 #include <sys/fcntl.h> 42 #include <sys/proc.h> 43 #include <sys/disk.h> 44 #include <sys/kauth.h> 45 46 #include <machine/intr.h> 47 #include <machine/bootconfig.h> 48 #include <machine/bootinfo.h> 49 #include <machine/config_hook.h> 50 51 static void handle_wedges(device_t dv, int par); 52 static int is_valid_disk(device_t dv); 53 static int match_bootdisk(device_t dv, struct btinfo_bootdisk *bid); 54 static void findroot(void); 55 56 void 57 cpu_configure(void) 58 { 59 60 splhigh(); 61 splserial(); 62 63 config_hook_init(); 64 65 if (config_rootfound("mainbus", NULL) == NULL) 66 panic("no mainbus found"); 67 68 /* Configuration is finished, turn on interrupts. */ 69 spl0(); 70 } 71 72 static void 73 handle_wedges(device_t dv, int par) 74 { 75 76 if (config_handle_wedges(dv, par) == 0) 77 return; 78 79 booted_device = dv; 80 booted_partition = par; 81 } 82 83 static int 84 is_valid_disk(device_t dv) 85 { 86 87 if (device_class(dv) != DV_DISK) 88 return 0; 89 90 return (device_is_a(dv, "dk") || 91 device_is_a(dv, "sd") || 92 device_is_a(dv, "wd") || 93 device_is_a(dv, "ld")); 94 } 95 96 /* 97 * Helper function for findroot(): 98 * Return non-zero if disk device matches bootinfo. 99 */ 100 static int 101 match_bootdisk(device_t dv, struct btinfo_bootdisk *bid) 102 { 103 struct vnode *tmpvn; 104 int error; 105 struct disklabel label; 106 int found = 0; 107 108 if (device_is_a(dv, "dk")) 109 return 0; 110 111 /* 112 * A disklabel is required here. The boot loader doesn't refuse 113 * to boot from a disk without a label, but this is normally not 114 * wanted. 115 */ 116 if (bid->labelsector == -1) 117 return 0; 118 119 if ((tmpvn = opendisk(dv)) == NULL) 120 return 0; 121 122 error = VOP_IOCTL(tmpvn, DIOCGDINFO, &label, FREAD, NOCRED); 123 if (error) { 124 /* 125 * XXX Can't happen -- open() would have errored out 126 * or faked one up. 127 */ 128 printf("match_bootdisk: can't get label for dev %s (%d)\n", 129 device_xname(dv), error); 130 goto closeout; 131 } 132 133 /* Compare with our data. */ 134 if (label.d_type == bid->label.type && 135 label.d_checksum == bid->label.checksum && 136 strncmp(label.d_packname, bid->label.packname, 16) == 0) 137 found = 1; 138 139 closeout: 140 VOP_CLOSE(tmpvn, FREAD, NOCRED); 141 vput(tmpvn); 142 return found; 143 } 144 145 static void 146 findroot(void) 147 { 148 struct btinfo_rootdevice *biv; 149 struct btinfo_bootdisk *bid; 150 device_t dv; 151 deviter_t di; 152 153 if (booted_device) 154 return; 155 156 if ((biv = lookup_bootinfo(BTINFO_ROOTDEVICE)) != NULL) { 157 for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); 158 dv != NULL; 159 dv = deviter_next(&di)) { 160 cfdata_t cd; 161 size_t len; 162 163 if (device_class(dv) != DV_DISK) 164 continue; 165 166 cd = device_cfdata(dv); 167 len = strlen(cd->cf_name); 168 169 if (strncmp(cd->cf_name, biv->devname, len) == 0 && 170 biv->devname[len] - '0' == cd->cf_unit) { 171 handle_wedges(dv, biv->devname[len + 1] - 'a'); 172 break; 173 } 174 } 175 deviter_release(&di); 176 if (dv != NULL) 177 return; 178 } 179 180 if ((bid = lookup_bootinfo(BTINFO_BOOTDISK)) != NULL) { 181 /* 182 * Scan all disk devices for ones that match the passed data. 183 * Don't break if one is found, to get possible multiple 184 * matches - for problem tracking. Use the first match anyway 185 * because lower device numbers are more likely to be the 186 * boot device. 187 */ 188 for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST); 189 dv != NULL; 190 dv = deviter_next(&di)) { 191 if (device_class(dv) != DV_DISK) 192 continue; 193 194 if (is_valid_disk(dv)) { 195 /* 196 * Don't trust BIOS device numbers, try 197 * to match the information passed by the 198 * boot loader instead. 199 */ 200 if ((bid->biosdev & 0x80) == 0 || 201 match_bootdisk(dv, bid) == 0) 202 continue; 203 goto bootdisk_found; 204 } 205 continue; 206 207 bootdisk_found: 208 if (booted_device) { 209 printf("WARNING: double match for boot " 210 "device (%s, %s)\n", 211 device_xname(booted_device), 212 device_xname(dv)); 213 continue; 214 } 215 handle_wedges(dv, bid->partition); 216 } 217 deviter_release(&di); 218 219 if (booted_device) 220 return; 221 } 222 } 223 224 void 225 cpu_rootconf(void) 226 { 227 228 findroot(); 229 230 aprint_normal("boot device: %s\n", 231 booted_device ? device_xname(booted_device) : "<unknown>"); 232 setroot(booted_device, booted_partition); 233 } 234 235 void 236 device_register(device_t dev, void *aux) 237 { 238 239 /* Nothing to do */ 240 } 241