fix root detection on evbarm when raid is involved there are several problems solved in this change: - lots of work was re-done when we already have determined the device booted from, so several new early returns introduced if booted_device has been set - due to the lack of cpu_bootconf(), raidframe softroot would override "root=xxx" on the boot command line - in the new cpu_bootconf(), switch the order of the platform boot-config with the set_root_device() call. this avoids a problem where "root=xxx" is checked after automated methods, and is thus ignored. - in fdt_detect_root_device(), remove the code to add "root=xxx"" string to the boot_args[] that would be later parsed by the set_root_device() call, and simply set booted_device and, for mbr installs, booted_partition directly. also, try to load the partition table, and if this partition is type MSDOS, choose partition 0 instead - for a normal/old mbr install, this means booting the msdos partition kernel will choose the ffs partition for root instead. also, for any successful call, perform an early return. - define __HAVE_CPU_BOOTCONF so early boot calls cpu_bootconf(). tested on: - rockpro64 booting from emmc, sata - rockpro64 loading kernel from msdos partition - rockpro64 booting from network (fails to auto-detect, with or without this change.) - quartz64 booting from nvme Index: arch/evbarm/evbarm/autoconf.c =================================================================== RCS file: /cvsroot/src/sys/arch/evbarm/evbarm/autoconf.c,v retrieving revision 1.23 diff -p -u -r1.23 autoconf.c --- arch/evbarm/evbarm/autoconf.c 19 Dec 2020 21:54:00 -0000 1.23 +++ arch/evbarm/evbarm/autoconf.c 27 Jan 2023 07:22:31 -0000 @@ -108,6 +108,9 @@ set_root_device(void) char *ptr, *end, *buf; size_t len; + if (booted_device) + return; + if (boot_args == NULL) return; @@ -118,7 +121,7 @@ set_root_device(void) return; /* NUL-terminate string, get_bootconf_option doesn't */ - for (end=ptr; *end != '\0'; ++end) { + for (end = ptr; *end != '\0'; ++end) { if (*end == ' ' || *end == '\t') { break; } @@ -144,16 +147,25 @@ set_root_device(void) #endif /* - * Set up the root device from the boot args + * Set up the root device from the boot args. + * + * cpu_bootconf() is called before RAIDframe root detection, + * and cpu_rootconf() is called after. */ void -cpu_rootconf(void) +cpu_bootconf(void) { #ifndef MEMORY_DISK_IS_ROOT + set_root_device(); if (evbarm_cpu_rootconf) (*evbarm_cpu_rootconf)(); - set_root_device(); #endif +} + +void +cpu_rootconf(void) +{ + cpu_bootconf(); aprint_normal("boot device: %s\n", booted_device != NULL ? device_xname(booted_device) : ""); rootconf(); Index: arch/evbarm/fdt/fdt_machdep.c =================================================================== RCS file: /cvsroot/src/sys/arch/evbarm/fdt/fdt_machdep.c,v retrieving revision 1.99 diff -p -u -r1.99 fdt_machdep.c --- arch/evbarm/fdt/fdt_machdep.c 4 Nov 2022 10:51:17 -0000 1.99 +++ arch/evbarm/fdt/fdt_machdep.c 27 Jan 2023 07:22:31 -0000 @@ -738,19 +738,42 @@ delay(u_int us) plat->ap_delay(us); } +/* + * Check if we're booted from an MSDOS partition, look for a + * reasonable boot partition on this disk that is large enough. + */ +static int +choose_root_part(struct disklabel *label, int part) +{ + /* Arbitrary 100 MiB size or root. */ + const uint32_t minroot = 1024 * 1024 * 100; + + /* return part if not msdos */ + if (label->d_partitions[part].p_fstype != FS_MSDOS) + return part; + + for (int n = 0; n < label->d_npartitions; n++) { + if (label->d_partitions[n].p_size >= minroot && + (label->d_partitions[n].p_fstype == FS_BSDFFS || + label->d_partitions[n].p_fstype == FS_BSDLFS || + label->d_partitions[n].p_fstype == FS_ISO9660 || + label->d_partitions[n].p_fstype == FS_APPLEUFS || + label->d_partitions[n].p_fstype == FS_EX2FS || + label->d_partitions[n].p_fstype == FS_RAID)) + return n; + } + + /* Nothing else, try it anyway. */ + return part; +} + static void fdt_detect_root_device(device_t dev) { - struct mbr_sector mbr; - uint8_t buf[DEV_BSIZE]; - uint8_t hash[16]; - const uint8_t *rhash; - char rootarg[64]; - struct vnode *vp; - MD5_CTX md5ctx; int error, len; - size_t resid; - u_int part; + + if (booted_device) + return; const int chosen = OF_finddevice("/chosen"); if (chosen < 0) @@ -758,6 +781,15 @@ fdt_detect_root_device(device_t dev) if (of_hasprop(chosen, "netbsd,mbr") && of_hasprop(chosen, "netbsd,partition")) { + struct disklabel label; + struct mbr_sector mbr; + uint8_t buf[DEV_BSIZE]; + uint8_t hash[16]; + const uint8_t *rhash; + struct vnode *vp; + MD5_CTX md5ctx; + size_t resid; + u_int part; /* * The bootloader has passed in a partition index and MD5 hash @@ -776,7 +808,13 @@ fdt_detect_root_device(device_t dev) return; error = vn_rdwr(UIO_READ, vp, buf, sizeof(buf), 0, UIO_SYSSPACE, IO_NODELOCKED, NOCRED, &resid, NULL); + if (error == 0) { + VOP_UNLOCK(vp); + error = VOP_IOCTL(vp, DIOCGDINFO, &label, FREAD, NOCRED); + vn_lock(vp, LK_EXCLUSIVE | LK_RETRY); + } VOP_CLOSE(vp, FREAD, NOCRED); + vput(vp); if (error != 0) @@ -787,22 +825,27 @@ fdt_detect_root_device(device_t dev) MD5Update(&md5ctx, (void *)&mbr, sizeof(mbr)); MD5Final(hash, &md5ctx); - if (memcmp(rhash, hash, 16) != 0) - return; + if (memcmp(rhash, hash, 16) == 0) { + booted_device = dev; + booted_partition = choose_root_part(&label, part); + + if (part != booted_partition) + printf("boot: %s: using partition 0 instead of " + "MSDOS partition %u\n", + device_xname(dev), part); + } - snprintf(rootarg, sizeof(rootarg), " root=%s%c", device_xname(dev), part + 'a'); - strcat(boot_args, rootarg); + return; } if (of_hasprop(chosen, "netbsd,gpt-guid")) { - char guidbuf[UUID_STR_LEN]; - const struct uuid *guid = fdtbus_get_prop(chosen, "netbsd,gpt-guid", &len); - if (guid == NULL || len != 16) - return; + const struct uuid *guid = + fdtbus_get_prop(chosen, "netbsd,gpt-guid", &len); + + if (guid != NULL && len == 16) + booted_device = dev; - uuid_snprintf(guidbuf, sizeof(guidbuf), guid); - snprintf(rootarg, sizeof(rootarg), " root=wedge:%s", guidbuf); - strcat(boot_args, rootarg); + return; } if (of_hasprop(chosen, "netbsd,gpt-label")) { @@ -813,14 +856,20 @@ fdt_detect_root_device(device_t dev) device_t dv = dkwedge_find_by_wname(label); if (dv != NULL) booted_device = dv; + + return; } if (of_hasprop(chosen, "netbsd,booted-mac-address")) { - const uint8_t *macaddr = fdtbus_get_prop(chosen, "netbsd,booted-mac-address", &len); + const uint8_t *macaddr = + fdtbus_get_prop(chosen, "netbsd,booted-mac-address", &len); + struct ifnet *ifp; + int s; + if (macaddr == NULL || len != 6) return; - int s = pserialize_read_enter(); - struct ifnet *ifp; + + s = pserialize_read_enter(); IFNET_READER_FOREACH(ifp) { if (memcmp(macaddr, CLLADDR(ifp->if_sadl), len) == 0) { device_t dv = device_find_by_xname(ifp->if_xname); @@ -830,6 +879,8 @@ fdt_detect_root_device(device_t dev) } } pserialize_read_exit(s); + + return; } } Index: arch/evbarm/include/types.h =================================================================== RCS file: /cvsroot/src/sys/arch/evbarm/include/types.h,v retrieving revision 1.15 diff -p -u -r1.15 types.h --- arch/evbarm/include/types.h 1 Apr 2021 04:35:45 -0000 1.15 +++ arch/evbarm/include/types.h 27 Jan 2023 07:22:31 -0000 @@ -3,6 +3,8 @@ #ifndef _EVBARM_TYPES_H_ #define _EVBARM_TYPES_H_ +#define __HAVE_CPU_BOOTCONF + #ifdef __aarch64__ #include