1 /* $NetBSD: autoconf.c,v 1.11 2023/10/14 08:05:25 andvar Exp $ */ 2 3 /* 4 * Copyright (c) 1994 Christian E. Hopps 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 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Christian E. Hopps. 18 * 4. The name of the author may not be used to endorse or promote products 19 * derived from this software without specific prior written permission 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33 #include <sys/cdefs.h> 34 __KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.11 2023/10/14 08:05:25 andvar Exp $"); 35 36 #include <sys/param.h> 37 #include <sys/systm.h> 38 #include <sys/reboot.h> 39 #include <sys/conf.h> 40 #include <sys/buf.h> 41 #include <sys/device.h> 42 #include <sys/device_impl.h> /* XXX autoconf abuse */ 43 #include <sys/disklabel.h> 44 #include <sys/disk.h> 45 #include <sys/proc.h> 46 #include <sys/kernel.h> 47 #include <sys/cpu.h> 48 49 #include <amiga/amiga/cfdev.h> 50 #include <amiga/amiga/device.h> 51 #include <amiga/amiga/custom.h> 52 53 static void findroot(void); 54 55 u_long boot_partition; 56 57 int amiga_realconfig; 58 59 /* 60 * called at boot time, configure all devices on system 61 */ 62 void 63 cpu_configure(void) 64 { 65 66 /* 67 * this is the real thing baby (i.e. not console init) 68 */ 69 amiga_realconfig = 1; 70 custom.intena = INTF_INTEN; 71 72 if (config_rootfound("mainbus", NULL) == NULL) 73 panic("configure: mainbus not configured"); 74 75 #ifdef DEBUG_KERNEL_START 76 printf("survived autoconf, going to enable interrupts\n"); 77 #endif 78 79 genppc_cpu_configure(); 80 custom.intena = INTF_SETCLR | INTF_INTEN; 81 82 #ifdef DEBUG_KERNEL_START 83 printf("survived configure...\n"); 84 #endif 85 } 86 87 void 88 cpu_rootconf(void) 89 { 90 91 findroot(); 92 #ifdef DEBUG_KERNEL_START 93 printf("survived findroot()\n"); 94 #endif 95 rootconf(); 96 } 97 98 /*ARGSUSED*/ 99 int 100 simple_devprint(void *aux, const char *pnp) 101 { 102 103 return QUIET; 104 } 105 106 int 107 matchname(const char *fp, const char *sp) 108 { 109 int len; 110 111 len = strlen(fp); 112 if (strlen(sp) != len) 113 return 0; 114 if (bcmp(fp, sp, len) == 0) 115 return 1; 116 return 0; 117 } 118 119 /* 120 * use config_search_ia to find appropriate device, then call that device 121 * directly with NULL device variable storage. A device can then 122 * always tell the difference between the real and console init 123 * by checking for NULL. 124 */ 125 int 126 amiga_config_found(cfdata_t pcfp, device_t parent, void *aux, cfprint_t pfn, 127 const struct cfargs *cfargs) 128 { 129 struct device temp; 130 cfdata_t cf; 131 const struct cfattach *ca; 132 int rv = 0; 133 134 if (amiga_realconfig) { 135 rv = config_found(parent, aux, pfn, cfargs) != NULL; 136 goto out; 137 } 138 139 if (parent == NULL) { 140 memset(&temp, 0, sizeof temp); 141 parent = &temp; 142 } 143 144 parent->dv_cfdata = pcfp; 145 parent->dv_cfdriver = config_cfdriver_lookup(pcfp->cf_name); 146 parent->dv_unit = pcfp->cf_unit; 147 148 if ((cf = config_search(parent, aux, cfargs)) != NULL) { 149 ca = config_cfattach_lookup(cf->cf_name, cf->cf_atname); 150 if (ca != NULL) { 151 (*ca->ca_attach)(parent, NULL, aux); 152 rv = 1; 153 } 154 } 155 parent->dv_cfdata = NULL; 156 out: 157 return rv; 158 } 159 160 /* 161 * this function needs to get enough configured to do a console 162 * basically this means start attaching the grfxx's that support 163 * the console. Kinda hacky but it works. 164 */ 165 void 166 config_console(void) 167 { 168 cfdata_t cf; 169 170 config_init(); 171 172 /* 173 * we need mainbus' cfdata. 174 */ 175 cf = config_rootsearch(NULL, "mainbus", NULL); 176 if (cf == NULL) 177 panic("no mainbus"); 178 179 /* 180 * internal grf. 181 */ 182 amiga_config_found(cf, NULL, __UNCONST("grfcc"), NULL, CFARGS_NONE); 183 184 /* 185 * zbus knows when its not for real and will 186 * only configure the appropriate hardware 187 */ 188 amiga_config_found(cf, NULL, __UNCONST("zbus"), NULL, CFARGS_NONE); 189 } 190 191 /* 192 * The system will assign the "booted device" indicator (and thus 193 * rootdev if rootspec is wildcarded) to the first partition 'a' 194 * in preference of boot. However, it does walk unit backwards 195 * to remain compatible with the old Amiga method of picking the 196 * last root found. 197 */ 198 #include <sys/fcntl.h> /* XXXX and all that uses it */ 199 #include <sys/proc.h> /* XXXX and all that uses it */ 200 201 #include "fd.h" 202 #include "sd.h" 203 #include "cd.h" 204 #include "wd.h" 205 206 #if NFD > 0 207 extern struct cfdriver fd_cd; 208 extern const struct bdevsw fd_bdevsw; 209 #endif 210 #if NSD > 0 211 extern struct cfdriver sd_cd; 212 extern const struct bdevsw sd_bdevsw; 213 #endif 214 #if NCD > 0 215 extern struct cfdriver cd_cd; 216 extern const struct bdevsw cd_bdevsw; 217 #endif 218 #if NWD > 0 219 extern struct cfdriver wd_cd; 220 extern const struct bdevsw wd_bdevsw; 221 #endif 222 223 struct cfdriver *genericconf[] = { 224 #if NFD > 0 225 &fd_cd, 226 #endif 227 #if NSD > 0 228 &sd_cd, 229 #endif 230 #if NWD > 0 231 &wd_cd, 232 #endif 233 #if NCD > 0 234 &cd_cd, 235 #endif 236 NULL, 237 }; 238 239 void 240 findroot(void) 241 { 242 struct disk *dkp; 243 struct partition *pp; 244 device_t*devs; 245 int i, maj, unit; 246 const struct bdevsw *bdp; 247 248 #if NSD > 0 249 /* 250 * If we have the boot partition offset (boot_partition), try 251 * to locate the device corresponding to that partition. 252 */ 253 #ifdef DEBUG_KERNEL_START 254 printf("Boot partition offset is %ld\n", boot_partition); 255 #endif 256 if (boot_partition != 0) { 257 258 for (unit = 0; unit < sd_cd.cd_ndevs; ++unit) { 259 #ifdef DEBUG_KERNEL_START 260 printf("probing for sd%d\n", unit); 261 #endif 262 if (sd_cd.cd_devs[unit] == NULL) 263 continue; 264 265 /* 266 * Find the disk corresponding to the current 267 * device. 268 */ 269 devs = sd_cd.cd_devs; 270 if ((dkp = disk_find(device_xname(devs[unit]))) == NULL) 271 continue; 272 273 if (dkp->dk_driver == NULL || 274 dkp->dk_driver->d_strategy == NULL) 275 continue; 276 bdp = &sd_bdevsw; 277 maj = bdevsw_lookup_major(bdp); 278 if ((*bdp->d_open)(MAKEDISKDEV(maj, unit, RAW_PART), 279 FREAD | FNONBLOCK, 0, curlwp)) 280 continue; 281 (*bdp->d_close)(MAKEDISKDEV(maj, unit, RAW_PART), 282 FREAD | FNONBLOCK, 0, curlwp); 283 pp = &dkp->dk_label->d_partitions[0]; 284 for (i = 0; i < dkp->dk_label->d_npartitions; 285 i++, pp++) { 286 #ifdef DEBUG_KERNEL_START 287 printf("sd%d%c type %d offset %d size %d\n", 288 unit, i+'a', pp->p_fstype, 289 pp->p_offset, pp->p_size); 290 #endif 291 if (pp->p_size == 0 || 292 (pp->p_fstype != FS_BSDFFS && 293 pp->p_fstype != FS_SWAP)) 294 continue; 295 if (pp->p_offset == boot_partition) { 296 if (booted_device == NULL) { 297 booted_device = devs[unit]; 298 booted_partition = i; 299 } else 300 printf("Ambiguous boot device\n"); 301 } 302 } 303 } 304 } 305 if (booted_device != NULL) 306 return; /* we found the boot device */ 307 #endif 308 309 for (i = 0; genericconf[i] != NULL; i++) { 310 for (unit = genericconf[i]->cd_ndevs - 1; unit >= 0; unit--) { 311 if (genericconf[i]->cd_devs[unit] == NULL) 312 continue; 313 314 /* 315 * Find the disk structure corresponding to the 316 * current device. 317 */ 318 devs = genericconf[i]->cd_devs; 319 if ((dkp = disk_find(device_xname(devs[unit]))) == NULL) 320 continue; 321 322 if (dkp->dk_driver == NULL || 323 dkp->dk_driver->d_strategy == NULL) 324 continue; 325 326 bdp = NULL; 327 #if NFD > 0 328 if (fd_bdevsw.d_strategy == dkp->dk_driver->d_strategy) 329 bdp = &fd_bdevsw; 330 #endif 331 #if NSD > 0 332 if (sd_bdevsw.d_strategy == dkp->dk_driver->d_strategy) 333 bdp = &sd_bdevsw; 334 #endif 335 #if NWD > 0 336 if (wd_bdevsw.d_strategy == dkp->dk_driver->d_strategy) 337 bdp = &wd_bdevsw; 338 #endif 339 #if NCD > 0 340 if (cd_bdevsw.d_strategy == dkp->dk_driver->d_strategy) 341 bdp = &cd_bdevsw; 342 #endif 343 #ifdef DIAGNOSTIC 344 if (bdp == NULL) 345 panic("findroot: impossible"); 346 #endif 347 maj = bdevsw_lookup_major(bdp); 348 349 /* Open disk; forces read of disklabel. */ 350 if ((*bdp->d_open)(MAKEDISKDEV(maj, 351 unit, 0), FREAD|FNONBLOCK, 0, &lwp0)) 352 continue; 353 (void)(*bdp->d_close)(MAKEDISKDEV(maj, 354 unit, 0), FREAD|FNONBLOCK, 0, &lwp0); 355 356 pp = &dkp->dk_label->d_partitions[0]; 357 if (pp->p_size != 0 && pp->p_fstype == FS_BSDFFS) { 358 booted_device = devs[unit]; 359 booted_partition = 0; 360 return; 361 } 362 } 363 } 364 } 365 366 /* 367 * Try to determine, if this machine is an A3000, which has a builtin 368 * realtime clock and scsi controller, so that this hardware is only 369 * included as "configured" if this IS an A3000 370 */ 371 int a3000_flag = 1; /* patchable */ 372 #ifdef A4000 373 int a4000_flag = 1; /* patchable - default to A4000 */ 374 #else 375 int a4000_flag = 0; /* patchable */ 376 #endif 377 378 int 379 is_a3000(void) 380 { 381 /* this is a dirty kludge.. but how do you do this RIGHT ? :-) */ 382 extern long boot_fphystart; 383 short sc; 384 385 if ((machineid >> 16) == 3000) 386 return 1; /* It's an A3000 */ 387 if (machineid >> 16) 388 return 0; /* It's not an A3000 */ 389 /* Machine type is unknown, so try to guess it */ 390 /* where is fastram on the A4000 ?? */ 391 /* if fastram is below 0x07000000, assume it's not an A3000 */ 392 if (boot_fphystart < 0x07000000) 393 return 0; 394 /* 395 * OK, fastram starts at or above 0x07000000, check specific 396 * machines 397 */ 398 for (sc = 0; sc < ncfdev; sc++) { 399 switch (cfdev[sc].rom.manid) { 400 case 2026: /* Progressive Peripherals, Inc */ 401 switch (cfdev[sc].rom.prodid) { 402 case 0: /* PPI Mercury - A3000 */ 403 case 1: /* PP&S A3000 '040 */ 404 return 1; 405 case 150: /* PPI Zeus - it's an A2000 */ 406 case 105: /* PP&S A2000 '040 */ 407 case 187: /* PP&S A500 '040 */ 408 return 0; 409 } 410 break; 411 412 case 2112: /* IVS */ 413 switch (cfdev[sc].rom.prodid) { 414 case 242: 415 return 0; /* A2000 accelerator? */ 416 } 417 break; 418 } 419 } 420 return a3000_flag; /* XXX let flag tell now */ 421 } 422 423 int 424 is_a4000(void) 425 { 426 427 if ((machineid >> 16) == 4000) 428 return 1; /* It's an A4000 */ 429 if ((machineid >> 16) == 1200) 430 return 0; /* It's an A1200, so not A4000 */ 431 /* Do I need this any more? */ 432 if ((custom.deniseid & 0xff) == 0xf8) 433 return 1; 434 #ifdef DEBUG 435 if (a4000_flag) 436 printf("Denise ID = %04x\n", (unsigned short)custom.deniseid); 437 #endif 438 if (machineid >> 16) 439 return 0; /* It's not an A4000 */ 440 return a4000_flag; /* Machine type not set */ 441 } 442 443 int 444 is_a1200(void) 445 { 446 447 if ((machineid >> 16) == 1200) 448 return 1; /* It's an A1200 */ 449 return 0; /* Machine type not set */ 450 } 451