#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.11 2023/12/20 15:00:08 thorpej Exp $");
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
#include <sys/disklabel.h>
#include <sys/conf.h>
#include <sys/vnode.h>
#include <sys/fcntl.h>
#include <sys/disk.h>
#include <sys/proc.h>
#include <sys/kauth.h>
#include <machine/bootinfo.h>
#include <machine/intr.h>
void
cpu_configure(void)
{
splhigh();
intr_init();
if (config_rootfound("mainbus", NULL) == NULL)
panic("no mainbus found");
spl0();
}
static int
is_valid_disk(device_t dv)
{
const char *name;
if (device_class(dv) != DV_DISK)
return (0);
name = device_cfdata(dv)->cf_name;
return (strcmp(name, "sd") == 0 || strcmp(name, "wd") == 0 ||
strcmp(name, "ld") == 0);
}
static int
match_bootdisk(device_t dv, struct btinfo_bootdisk *bid)
{
struct vnode *tmpvn;
int error;
struct disklabel label;
int found = 0;
int bmajor;
if (bid->labelsector == -1)
return (0);
bmajor = devsw_name2blk(device_xname(dv), NULL, 0);
if (bmajor == -1)
return (0);
if (bdevvp(MAKEDISKDEV(bmajor, device_unit(dv), RAW_PART), &tmpvn))
panic("match_bootdisk: can't alloc vnode");
vn_lock(tmpvn, LK_EXCLUSIVE | LK_RETRY);
error = VOP_OPEN(tmpvn, FREAD, NOCRED);
if (error) {
#ifndef DEBUG
if (error != ENXIO && error != ENODEV)
#endif
aprint_error("match_bootdisk: can't open dev %s (%d)\n",
device_xname(dv), error);
vput(tmpvn);
return (0);
}
VOP_UNLOCK(tmpvn);
error = VOP_IOCTL(tmpvn, DIOCGDINFO, &label, FREAD, NOCRED);
if (error) {
aprint_error("match_bootdisk: can't get label for dev %s (%d)\n",
device_xname(dv), error);
goto closeout;
}
if (label.d_type == bid->label.type &&
label.d_checksum == bid->label.checksum &&
strncmp(label.d_packname, bid->label.packname, 16) == 0)
found = 1;
closeout:
vn_lock(tmpvn, LK_EXCLUSIVE | LK_RETRY);
VOP_CLOSE(tmpvn, FREAD, NOCRED);
vput(tmpvn);
return (found);
}
static void
findroot(void)
{
struct btinfo_bootdisk *bid;
device_t dv;
deviter_t di;
if (booted_device)
return;
if ((bid = lookup_bootinfo(BTINFO_BOOTDISK)) != NULL) {
for (dv = deviter_first(&di, DEVITER_F_ROOT_FIRST);
dv != NULL;
dv = deviter_next(&di)) {
if (device_class(dv) != DV_DISK)
continue;
if (is_valid_disk(dv)) {
if (match_bootdisk(dv, bid) == 0)
continue;
goto bootdisk_found;
}
continue;
bootdisk_found:
if (booted_device) {
aprint_error("WARNING: double match for boot "
"device (%s, %s)\n",
device_xname(booted_device), device_xname(dv));
continue;
}
booted_device = dv;
booted_partition = bid->partition;
}
deviter_release(&di);
if (booted_device)
return;
}
}
void
cpu_rootconf(void)
{
findroot();
aprint_normal("boot device: %s\n",
booted_device ? device_xname(booted_device) : "<unknown>");
rootconf();
}