Module Name: src Committed By: martin Date: Fri Sep 13 07:00:14 UTC 2019
Modified Files: src/share/man/man8/man8.x86 [netbsd-9]: boot.8 src/sys/arch/i386/stand/boot [netbsd-9]: boot2.c devopen.c devopen.h src/sys/arch/i386/stand/efiboot [netbsd-9]: boot.c devopen.c devopen.h efidisk.c src/sys/arch/i386/stand/lib [netbsd-9]: Makefile biosdisk.c biosdisk.h Log Message: Pull up following revision(s) (requested by manu in ticket #200): sys/arch/i386/stand/boot/boot2.c: revision 1.72 sys/arch/i386/stand/lib/biosdisk.c: revision 1.50 sys/arch/i386/stand/lib/biosdisk.c: revision 1.51 sys/arch/i386/stand/efiboot/devopen.c: revision 1.6 sys/arch/i386/stand/efiboot/devopen.h: revision 1.4 sys/arch/i386/stand/efiboot/devopen.c: revision 1.7 sys/arch/i386/stand/efiboot/efidisk.c: revision 1.8 share/man/man8/man8.x86/boot.8: revision 1.16 share/man/man8/man8.x86/boot.8: revision 1.17 sys/arch/i386/stand/lib/Makefile: revision 1.46 sys/arch/i386/stand/boot/devopen.h: revision 1.5 sys/arch/i386/stand/boot/devopen.c: revision 1.9 sys/arch/i386/stand/efiboot/boot.c: revision 1.14 sys/arch/i386/stand/efiboot/boot.c: revision 1.15 sys/arch/i386/stand/lib/biosdisk.h: revision 1.11 sys/arch/i386/stand/boot/boot2.c: revision 1.71 Add GPT and RAIDframe support to bootloaders Classic BIOS (/boot) and EFI bootloaders can now name devices using the NAME=gpt_label syntax, or using raid partitions. Here are examples: boot NAME=root:/netbsd boot raid0e:/netbsd Correct the memset(3)'s third argument in i386 biosdisk.c The size of allocation is the size of the structure biosdisk, not the size of a pointer. Document new GPT and RAIDframe capacity of bootstrap code While there, also document EFI setup and some bugs Typo fixes, 'file system'; new sentence, new line; expand IA-32. Bump date for previous. Make sure devices names are copied including last byte Fix from M. Levinson. To generate a diff of this commit: cvs rdiff -u -r1.15 -r1.15.2.1 src/share/man/man8/man8.x86/boot.8 cvs rdiff -u -r1.70 -r1.70.8.1 src/sys/arch/i386/stand/boot/boot2.c cvs rdiff -u -r1.8 -r1.8.64.1 src/sys/arch/i386/stand/boot/devopen.c cvs rdiff -u -r1.4 -r1.4.64.1 src/sys/arch/i386/stand/boot/devopen.h cvs rdiff -u -r1.13 -r1.13.2.1 src/sys/arch/i386/stand/efiboot/boot.c cvs rdiff -u -r1.5 -r1.5.6.1 src/sys/arch/i386/stand/efiboot/devopen.c cvs rdiff -u -r1.3 -r1.3.6.1 src/sys/arch/i386/stand/efiboot/devopen.h cvs rdiff -u -r1.7 -r1.7.4.1 src/sys/arch/i386/stand/efiboot/efidisk.c cvs rdiff -u -r1.45 -r1.45.8.1 src/sys/arch/i386/stand/lib/Makefile cvs rdiff -u -r1.49 -r1.49.6.1 src/sys/arch/i386/stand/lib/biosdisk.c cvs rdiff -u -r1.10 -r1.10.6.1 src/sys/arch/i386/stand/lib/biosdisk.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/share/man/man8/man8.x86/boot.8 diff -u src/share/man/man8/man8.x86/boot.8:1.15 src/share/man/man8/man8.x86/boot.8:1.15.2.1 --- src/share/man/man8/man8.x86/boot.8:1.15 Wed May 15 17:35:02 2019 +++ src/share/man/man8/man8.x86/boot.8 Fri Sep 13 07:00:14 2019 @@ -1,4 +1,4 @@ -.\" $NetBSD: boot.8,v 1.15 2019/05/15 17:35:02 maxv Exp $ +.\" $NetBSD: boot.8,v 1.15.2.1 2019/09/13 07:00:14 martin Exp $ .\" .\" Copyright (c) 1991, 1993 .\" The Regents of the University of California. All rights reserved. @@ -32,7 +32,7 @@ .\" .\" @(#)boot_i386.8 8.2 (Berkeley) 4/19/94 .\" -.Dd May 15, 2019 +.Dd August 18, 2019 .Dt BOOT 8 x86 .Os .Sh NAME @@ -40,13 +40,9 @@ .Nd system bootstrapping procedures .Sh DESCRIPTION -.Tn IA-32 -computers -.Po -the +Intel Architecture, 32-bit (IA-32) computers (the .Tn IBM PC -and its clones -.Pc +and its clones) that can run .Nx Ns /i386 or @@ -60,6 +56,11 @@ bootstrap .Nx from the system .Tn BIOS +.It efiboot +bootstrap +.Nx +from the system +.Tn UEFI .It Xr x86/dosboot 8 bootstrap .Nx @@ -175,12 +176,32 @@ input of these commands: .It Ic boot Oo Va device : Oc Ns Oo Va filename Oc Oo Fl 1234abcdmqsvxz Oc The default .Va device -will be set to the disk that the boot loader was -loaded from. +will be set to the disk from which the boot loader was loaded. +The partition is set to the first match in this list: +.Bl -enum -compact +.It +The first +.Xr gpt 8 +partition with the +.Va bootme +attribute set. +.It +The partition from which the boot loader was loaded from, if that +can be detected. +.It +The first partition with a file system that could be bootable. +.It +The first partition. +.El To boot from an alternate disk, the full name of the device should be given at the prompt. .Va device is of the form +.Va NAME=partition_label +when booting from a +.Xr gpt 8 +partitioned disk. +Otherwise, the syntax is .Xo Va xd .Op Va N Ns Op Va x .Xc @@ -192,8 +213,8 @@ is the unit number, and .Va x is the partition letter. .Pp -The following list of supported devices may vary from installation to -installation: +In the later case, the following list of supported devices may +vary from installation to installation: .Pp .Bl -hang -compact .It hd @@ -203,6 +224,22 @@ lookalike controller(s), and SCSI disks on SCSI controllers recognized by the BIOS. .It fd Floppy drives as numbered by the BIOS. +.It cd +CD-ROM drives as numbered by the BIOS. +.It raid +RAIDframe configured from hard disks recognized by the BIOS. +Only RAID level 1 sets are supported by bootstrap code. +If the RAID is partitioned, the first partition is used, or the +first +.Xr gpt 8 +partition that has the +.Va bootme +attribute set. +Inner RAIDframe partitions can also be given to the +.Ic dev +command using he +.Va NAME=partition_label +syntax. .El .Pp The default @@ -700,6 +737,33 @@ the .Nx partition by .Xr installboot 8 . +.It Pa /usr/mdec/bootia32.efi +.It Pa /usr/mdec/bootx64.efi +.Tn UEFI +bootstraps for +.Nx Ns /i386 +and +.Nx Ns /amd64 , +which should be copied to the +.Pa /efi/boot +directory in a +.Tn FAT +formatted partition of type +.Tn EFI +(Either +.Xr mbr 8 +and +.Xr gpt 8 , +see the +.Sx BUGS +section). +.Nx +.Tn UEFI +bootstrap reads its configuration from the +.Pa /efi/netBSD/boot.cfg +file in the +.Tn EFI +partition. .El .Sh SEE ALSO .Xr ddb 4 , @@ -756,3 +820,44 @@ is derived from the field of the .Nx disklabel (if it is a hard disk). +.Pp +.Ic multiboot +is not supported by +.Tn UEFI +bootstrap code. +.Pp +.Tn UEFI +implementation are supposed to support either +.Xr mbr 8 +or +.Xr gpt 8 +partitionning, but some do not handle the later. +.Tn UEFI +Booting +from a +.Xr gpt 8 +partitioned disk is still possible in this case, by adding +an overlapping +.Tn EFI +partition in the protective +.Xr mbr 8 +block. +This can be achieved using the following commands +(you must adapt the hard disk and +.Tn EFI +partition start end size to fit your setup): +.Dl Ic dd if=/dev/rwd0d bs=512 count=1 of=mbr +.Dl Ic fdisk -FIfaui1s 4/34/32768 -c /usr/mdec/mbr mbr +.Dl Ic dd if=mbr bs=512 count=1 of=/dev/rwd0d conv=notrunc +The resulting +.Xr mbr 8 +partition table will look like this: +.Bd -unfilled -offset indent +0: GPT Protective MBR (sysid 238) + start 1, size 2097151 (1024 MB, Cyls 0-130/138/8) + PBR is not bootable: Bad magic number (0x0000) +1: Primary DOS with 16 bit FAT <32M (sysid 4) + start 34, size 32768 (16 MB, Cyls 0/0/35-2/10/42), Active +2: <UNUSED> +3: <UNUSED> +.Ed Index: src/sys/arch/i386/stand/boot/boot2.c diff -u src/sys/arch/i386/stand/boot/boot2.c:1.70 src/sys/arch/i386/stand/boot/boot2.c:1.70.8.1 --- src/sys/arch/i386/stand/boot/boot2.c:1.70 Tue Nov 14 09:55:41 2017 +++ src/sys/arch/i386/stand/boot/boot2.c Fri Sep 13 07:00:13 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: boot2.c,v 1.70 2017/11/14 09:55:41 maxv Exp $ */ +/* $NetBSD: boot2.c,v 1.70.8.1 2019/09/13 07:00:13 martin Exp $ */ /*- * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc. @@ -79,6 +79,7 @@ #include <libi386.h> #include <bootmod.h> #include <bootmenu.h> +#include <biosdisk.h> #include <vbe.h> #include "devopen.h" @@ -104,11 +105,16 @@ static const char * const names[][2] = { #define NUMNAMES (sizeof(names)/sizeof(names[0])) #define DEFFILENAME names[0][0] +#ifndef NO_GPT +#define MAXDEVNAME 39 /* "NAME=" + 34 char part_name */ +#else #define MAXDEVNAME 16 +#endif static char *default_devname; static int default_unit, default_partition; static const char *default_filename; +static const char *default_part_name; char *sprint_bootsel(const char *); static void bootit(const char *, int); @@ -160,9 +166,16 @@ parsebootfile(const char *fname, char ** int *unit, int *partition, const char **file) { const char *col; + static char savedevname[MAXDEVNAME+1]; *fsname = "ufs"; - *devname = default_devname; + if (default_part_name == NULL) { + *devname = default_devname; + } else { + snprintf(savedevname, sizeof(savedevname), + "NAME=%s", default_part_name); + *devname = savedevname; + } *unit = default_unit; *partition = default_partition; *file = default_filename; @@ -171,7 +184,6 @@ parsebootfile(const char *fname, char ** return 0; if ((col = strchr(fname, ':')) != NULL) { /* device given */ - static char savedevname[MAXDEVNAME+1]; int devlen; int u = 0, p = 0; int i = 0; @@ -180,6 +192,17 @@ parsebootfile(const char *fname, char ** if (devlen > MAXDEVNAME) return EINVAL; +#ifndef NO_GPT + if (strstr(fname, "NAME=") == fname) { + strlcpy(savedevname, fname, devlen + 1); + *devname = savedevname; + *unit = -1; + *partition = -1; + fname = col + 1; + goto out; + } +#endif + #define isvalidname(c) ((c) >= 'a' && (c) <= 'z') if (!isvalidname(fname[i])) return EINVAL; @@ -215,6 +238,7 @@ parsebootfile(const char *fname, char ** fname = col + 1; } +out: if (*fname) *file = fname; @@ -231,8 +255,11 @@ sprint_bootsel(const char *filename) if (parsebootfile(filename, &fsname, &devname, &unit, &partition, &file) == 0) { - snprintf(buf, sizeof(buf), "%s%d%c:%s", devname, unit, - 'a' + partition, file); + if (strstr(devname, "NAME=") == devname) + snprintf(buf, sizeof(buf), "%s:%s", devname, file); + else + snprintf(buf, sizeof(buf), "%s%d%c:%s", devname, unit, + 'a' + partition, file); return buf; } return "(invalid)"; @@ -319,7 +346,7 @@ boot2(int biosdev, uint64_t biossector) /* try to set default device to what BIOS tells us */ bios2dev(biosdev, biossector, &default_devname, &default_unit, - &default_partition); + &default_partition, &default_part_name); /* if the user types "boot" without filename */ default_filename = DEFFILENAME; @@ -401,13 +428,21 @@ command_help(char *arg) { printf("commands are:\n" - "boot [xdNx:][filename] [-12acdqsvxz]\n" + "boot [dev:][filename] [-12acdqsvxz]\n" +#ifndef NO_RAIDFRAME + " dev syntax is (hd|fd|cd|raid)[N[x]]\n" +#else + " dev syntax is (hd|fd|cd)[N[x]]n" +#endif +#ifndef NO_GPT + " or NAME=gpt_label\n" +#endif " (ex. \"hd0a:netbsd.old -s\")\n" - "pkboot [xdNx:][filename] [-12acdqsvxz]\n" + "pkboot [dev:][filename] [-12acdqsvxz]\n" #if LIBSA_ENABLE_LS_OP - "ls [path]\n" + "ls [dev:][path]\n" #endif - "dev xd[N[x]]:\n" + "dev [dev:]\n" "consdev {pc|com[0123]|com[0123]kbd|auto}\n" "vesa {modenum|on|off|enabled|disabled|list}\n" #ifndef SMALL @@ -415,7 +450,7 @@ command_help(char *arg) #endif "modules {on|off|enabled|disabled}\n" "load {path_to_module}\n" - "multiboot [xdNx:][filename] [<args>]\n" + "multiboot [dev:][filename] [<args>]\n" "splash {path_to_image_file}\n" "userconf {command}\n" "rndseed {path_to_rndseed_file}\n" @@ -490,8 +525,16 @@ command_dev(char *arg) if (*arg == '\0') { biosdisk_probe(); - printf("default %s%d%c\n", default_devname, default_unit, - 'a' + default_partition); + +#ifndef NO_GPT + if (default_part_name) + printf("default NAME=%s on %s%d\n", default_part_name, + default_devname, default_unit); + else +#endif + printf("default %s%d%c\n", + default_devname, default_unit, + 'a' + default_partition); return; } @@ -505,6 +548,10 @@ command_dev(char *arg) /* put to own static storage */ strncpy(savedevname, devname, MAXDEVNAME + 1); default_devname = savedevname; + + /* +5 to skip leading NAME= */ + if (strstr(devname, "NAME=") == devname) + default_part_name = default_devname + 5; } static const struct cons_devs { Index: src/sys/arch/i386/stand/boot/devopen.c diff -u src/sys/arch/i386/stand/boot/devopen.c:1.8 src/sys/arch/i386/stand/boot/devopen.c:1.8.64.1 --- src/sys/arch/i386/stand/boot/devopen.c:1.8 Fri Dec 24 20:40:42 2010 +++ src/sys/arch/i386/stand/boot/devopen.c Fri Sep 13 07:00:13 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: devopen.c,v 1.8 2010/12/24 20:40:42 jakllsch Exp $ */ +/* $NetBSD: devopen.c,v 1.8.64.1 2019/09/13 07:00:13 martin Exp $ */ /*- * Copyright (c) 2005 The NetBSD Foundation, Inc. @@ -89,7 +89,8 @@ dev2bios(char *devname, int unit, int *b } void -bios2dev(int biosdev, daddr_t sector, char **devname, int *unit, int *partition) +bios2dev(int biosdev, daddr_t sector, char **devname, int *unit, + int *partition, const char **part_name) { /* set default */ @@ -109,7 +110,7 @@ bios2dev(int biosdev, daddr_t sector, ch } else *devname = "fd"; - *partition = biosdisk_findpartition(biosdev, sector); + (void)biosdisk_findpartition(biosdev, sector, partition, part_name); } #ifdef _STANDALONE @@ -128,9 +129,9 @@ devopen(struct open_file *f, const char int biosdev; int error; - if ((error = parsebootfile(fname, &fsname, &devname, - &unit, &partition, (const char **) file)) - || (error = dev2bios(devname, unit, &biosdev))) + error = parsebootfile(fname, &fsname, &devname, + &unit, &partition, (const char **) file); + if (error) return error; f->f_dev = &devsw[0]; /* must be biosdisk */ @@ -142,5 +143,26 @@ devopen(struct open_file *f, const char } #endif +#ifndef NO_GPT + /* Search by GPT label name */ + if (strstr(devname, "NAME=") == devname) { + f->f_dev = &devsw[0]; /* must be biosdisk */ + + return biosdisk_open_name(f, devname); + } +#endif +#ifndef NO_RAIDFRAME + /* Search by raidframe name */ + if (strstr(devname, "raid") == devname) { + f->f_dev = &devsw[0]; /* must be biosdisk */ + + return biosdisk_open_name(f, devname); + } +#endif + + error = dev2bios(devname, unit, &biosdev); + if (error) + return error; + return biosdisk_open(f, biosdev, partition); } Index: src/sys/arch/i386/stand/boot/devopen.h diff -u src/sys/arch/i386/stand/boot/devopen.h:1.4 src/sys/arch/i386/stand/boot/devopen.h:1.4.64.1 --- src/sys/arch/i386/stand/boot/devopen.h:1.4 Fri Dec 24 20:40:42 2010 +++ src/sys/arch/i386/stand/boot/devopen.h Fri Sep 13 07:00:13 2019 @@ -1,5 +1,5 @@ -/* $NetBSD: devopen.h,v 1.4 2010/12/24 20:40:42 jakllsch Exp $ */ +/* $NetBSD: devopen.h,v 1.4.64.1 2019/09/13 07:00:13 martin Exp $ */ extern int boot_biosdev; -void bios2dev(int, daddr_t, char **, int *, int *); +void bios2dev(int, daddr_t, char **, int *, int *, const char **); Index: src/sys/arch/i386/stand/efiboot/boot.c diff -u src/sys/arch/i386/stand/efiboot/boot.c:1.13 src/sys/arch/i386/stand/efiboot/boot.c:1.13.2.1 --- src/sys/arch/i386/stand/efiboot/boot.c:1.13 Mon Jul 29 11:28:51 2019 +++ src/sys/arch/i386/stand/efiboot/boot.c Fri Sep 13 07:00:13 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: boot.c,v 1.13 2019/07/29 11:28:51 nonaka Exp $ */ +/* $NetBSD: boot.c,v 1.13.2.1 2019/09/13 07:00:13 martin Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -35,6 +35,7 @@ #include "bootcfg.h" #include "bootmod.h" #include "bootmenu.h" +#include "biosdisk.h" #include "devopen.h" int errno; @@ -113,6 +114,7 @@ const struct bootblk_command commands[] static char *default_devname; static int default_unit, default_partition; static const char *default_filename; +static const char *default_part_name; static char *sprint_bootsel(const char *); static void bootit(const char *, int); @@ -122,9 +124,16 @@ parsebootfile(const char *fname, char ** int *partition, const char **file) { const char *col; + static char savedevname[MAXDEVNAME+1]; *fsname = "ufs"; - *devname = default_devname; + if (default_part_name == NULL) { + *devname = default_devname; + } else { + snprintf(savedevname, sizeof(savedevname), + "NAME=%s", default_part_name); + *devname = savedevname; + } *unit = default_unit; *partition = default_partition; *file = default_filename; @@ -133,7 +142,6 @@ parsebootfile(const char *fname, char ** return 0; if ((col = strchr(fname, ':')) != NULL) { /* device given */ - static char savedevname[MAXDEVNAME+1]; int devlen; int u = 0, p = 0; int i = 0; @@ -142,6 +150,15 @@ parsebootfile(const char *fname, char ** if (devlen > MAXDEVNAME) return EINVAL; + if (strstr(fname, "NAME=") == fname) { + strlcpy(savedevname, fname, devlen + 1); + *devname = savedevname; + *unit = -1; + *partition = -1; + fname = col + 1; + goto out; + } + #define isvalidname(c) ((c) >= 'a' && (c) <= 'z') if (!isvalidname(fname[i])) return EINVAL; @@ -177,6 +194,7 @@ parsebootfile(const char *fname, char ** fname = col + 1; } +out: if (*fname) *file = fname; @@ -193,8 +211,11 @@ snprint_bootdev(char *buf, size_t bufsiz for (i = 0; i < __arraycount(no_partition_devs); i++) if (strcmp(devname, no_partition_devs[i]) == 0) break; - snprintf(buf, bufsize, "%s%d%c", devname, unit, - i < __arraycount(no_partition_devs) ? '\0' : 'a' + partition); + if (strstr(devname, "NAME=") == devname) + strlcpy(buf, devname, bufsize); + else + snprintf(buf, bufsize, "%s%d%c", devname, unit, + i < __arraycount(no_partition_devs) ? '\0' : 'a' + partition); return buf; } @@ -262,7 +283,7 @@ boot(void) /* try to set default device to what BIOS tells us */ bios2dev(boot_biosdev, boot_biossector, &default_devname, &default_unit, - &default_partition); + &default_partition, &default_part_name); /* if the user types "boot" without filename */ default_filename = DEFFILENAME; @@ -339,24 +360,32 @@ command_help(char *arg) { printf("commands are:\n" - "boot [xdNx:][filename] [-12acdqsvxz]\n" + "boot [dev:][filename] [-12acdqsvxz]\n" +#ifndef NO_RAIDFRAME + " dev syntax is (hd|fd|cd|raid)[N[x]]\n" +#else + " dev syntax is (hd|fd|cd)[N[x]]\n" +#endif +#ifndef NO_GPT + " or NAME=gpt_label\n" +#endif " (ex. \"hd0a:netbsd.old -s\")\n" - "pkboot [xdNx:][filename] [-12acdqsvxz]\n" - "dev [xd[N[x]]:]\n" + "pkboot [dev:][filename] [-12acdqsvxz]\n" + "dev [dev:]\n" "consdev {pc|com[0123][,{speed}]|com,{ioport}[,{speed}]}\n" "devpath\n" "efivar\n" "gop [{modenum|list}]\n" "load {path_to_module}\n" #if LIBSA_ENABLE_LS_OP - "ls [path]\n" + "ls [dev:][path]\n" #endif "memmap [{sorted|unsorted|compact}]\n" #ifndef SMALL "menu (reenters boot menu, if defined in boot.cfg)\n" #endif "modules {on|off|enabled|disabled}\n" - "multiboot [xdNx:][filename] [<args>]\n" + "multiboot [dev:][filename] [<args>]\n" "rndseed {path_to_rndseed_file}\n" "splash {path_to_image_file}\n" "text [{modenum|list}]\n" @@ -433,8 +462,14 @@ command_dev(char *arg) if (*arg == '\0') { efi_disk_show(); efi_net_show(); - printf("default %s\n", snprint_bootdev(buf, sizeof(buf), - default_devname, default_unit, default_partition)); + + if (default_part_name != NULL) + printf("default NAME=%s\n", default_part_name); + else + printf("default %s\n", + snprint_bootdev(buf, sizeof(buf), + default_devname, default_unit, + default_partition)); return; } @@ -448,6 +483,10 @@ command_dev(char *arg) /* put to own static storage */ strncpy(savedevname, devname, MAXDEVNAME + 1); default_devname = savedevname; + + /* +5 to skip leading NAME= */ + if (strstr(devname, "NAME=") == devname) + default_part_name = default_devname + 5; } static const struct cons_devs { Index: src/sys/arch/i386/stand/efiboot/devopen.c diff -u src/sys/arch/i386/stand/efiboot/devopen.c:1.5 src/sys/arch/i386/stand/efiboot/devopen.c:1.5.6.1 --- src/sys/arch/i386/stand/efiboot/devopen.c:1.5 Wed Apr 11 10:32:09 2018 +++ src/sys/arch/i386/stand/efiboot/devopen.c Fri Sep 13 07:00:13 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: devopen.c,v 1.5 2018/04/11 10:32:09 nonaka Exp $ */ +/* $NetBSD: devopen.c,v 1.5.6.1 2019/09/13 07:00:13 martin Exp $ */ /*- * Copyright (c) 2005 The NetBSD Foundation, Inc. @@ -78,8 +78,10 @@ dev2bios(char *devname, int unit, int *b } void -bios2dev(int biosdev, daddr_t sector, char **devname, int *unit, int *partition) +bios2dev(int biosdev, daddr_t sector, char **devname, int *unit, + int *partition, const char **part_name) { + static char savedevname[MAXDEVNAME+1]; *unit = biosdev & 0x7f; @@ -96,7 +98,12 @@ bios2dev(int biosdev, daddr_t sector, ch } else *devname = "hd"; - *partition = biosdisk_findpartition(biosdev, sector); + (void)biosdisk_findpartition(biosdev, sector, partition, part_name); + if (*part_name != NULL) { + snprintf(savedevname, sizeof(savedevname), + "NAME=%s", *part_name); + *devname = savedevname; + } } struct btinfo_bootpath bibp; @@ -130,6 +137,20 @@ devopen(struct open_file *f, const char if (error) return error; + /* Search by GPT label or raidframe name */ + if ((strstr(devname, "NAME=") == devname) || + (strstr(devname, "raid") == devname)) { + f->f_dev = &devsw[0]; /* must be biosdisk */ + + if (!kernel_loaded) { + strncpy(bibp.bootpath, *file, sizeof(bibp.bootpath)); + BI_ADD(&bibp, BTINFO_BOOTPATH, sizeof(bibp)); + } + + error = biosdisk_open_name(f, devname); + return error; + } + memcpy(file_system, file_system_disk, sizeof(*file_system) * nfsys); nfsys = nfsys_disk; @@ -194,7 +215,7 @@ devopen(struct open_file *f, const char */ if (strcmp(devname, "esp") == 0) { bios2dev(boot_biosdev, boot_biossector, &devname, &unit, - &partition); + &partition, NULL); if (efidisk_get_efi_system_partition(boot_biosdev, &partition)) return ENXIO; } Index: src/sys/arch/i386/stand/efiboot/devopen.h diff -u src/sys/arch/i386/stand/efiboot/devopen.h:1.3 src/sys/arch/i386/stand/efiboot/devopen.h:1.3.6.1 --- src/sys/arch/i386/stand/efiboot/devopen.h:1.3 Wed Apr 11 10:32:09 2018 +++ src/sys/arch/i386/stand/efiboot/devopen.h Fri Sep 13 07:00:13 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: devopen.h,v 1.3 2018/04/11 10:32:09 nonaka Exp $ */ +/* $NetBSD: devopen.h,v 1.3.6.1 2019/09/13 07:00:13 martin Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -34,9 +34,9 @@ extern struct fs_ops file_system_nfs; extern struct fs_ops file_system_tftp; extern struct fs_ops file_system_null; -#define MAXDEVNAME 16 +#define MAXDEVNAME 39 /* mxmimum is "NAME=" + 34 char part_name */ -void bios2dev(int, daddr_t, char **, int *, int *); +void bios2dev(int, daddr_t, char **, int *, int *, const char **); struct devdesc { char d_name[MAXDEVNAME]; Index: src/sys/arch/i386/stand/efiboot/efidisk.c diff -u src/sys/arch/i386/stand/efiboot/efidisk.c:1.7 src/sys/arch/i386/stand/efiboot/efidisk.c:1.7.4.1 --- src/sys/arch/i386/stand/efiboot/efidisk.c:1.7 Wed Apr 17 06:50:34 2019 +++ src/sys/arch/i386/stand/efiboot/efidisk.c Fri Sep 13 07:00:13 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: efidisk.c,v 1.7 2019/04/17 06:50:34 nonaka Exp $ */ +/* $NetBSD: efidisk.c,v 1.7.4.1 2019/09/13 07:00:13 martin Exp $ */ /*- * Copyright (c) 2016 Kimihiro Nonaka <non...@netbsd.org> @@ -30,7 +30,9 @@ #include "efiboot.h" +#include <sys/param.h> /* for howmany, required by <dev/raidframe/raidframevar.h> */ #include <sys/disklabel.h> +#include <sys/disklabel_gpt.h> #include "biosdisk.h" #include "biosdisk_ll.h" @@ -40,6 +42,40 @@ static struct efidiskinfo_lh efi_disklist; static int nefidisks; +#define MAXDEVNAME 39 /* "NAME=" + 34 char part_name */ + +#include <dev/raidframe/raidframevar.h> +#define RF_COMPONENT_INFO_OFFSET 16384 /* from sys/dev/raidframe/rf_netbsdkintf.c */ +#define RF_COMPONENT_LABEL_VERSION 2 /* from <dev/raidframe/rf_raid.h> */ + +#define RAIDFRAME_NDEV 16 /* abitrary limit to 15 raidframe devices */ +struct efi_raidframe { + int last_unit; + int serial; + const struct efidiskinfo *edi; + int parent_part; + char parent_name[MAXDEVNAME + 1]; + daddr_t offset; + daddr_t size; +}; + +static void +dealloc_biosdisk_part(struct biosdisk_partition *part, int nparts) +{ + int i; + + for (i = 0; i < nparts; i++) { + if (part[i].part_name != NULL) { + dealloc(part[i].part_name, BIOSDISK_PART_NAME_LEN); + part[i].part_name = NULL; + } + } + + dealloc(part, sizeof(*part) * nparts); + + return; +} + void efi_disk_probe(void) { @@ -124,14 +160,51 @@ next: } } +static void +efi_raidframe_probe(struct efi_raidframe *raidframe, int *raidframe_count, + const struct efidiskinfo *edi, + struct biosdisk_partition *part, int parent_part) + +{ + int i = *raidframe_count; + struct RF_ComponentLabel_s label; + + if (i + 1 > RAIDFRAME_NDEV) + return; + + if (biosdisk_read_raidframe(edi->dev, part->offset, &label) != 0) + return; + + if (label.version != RF_COMPONENT_LABEL_VERSION) + return; + + raidframe[i].last_unit = label.last_unit; + raidframe[i].serial = label.serial_number; + raidframe[i].edi = edi; + raidframe[i].parent_part = parent_part; + if (part->part_name) + strlcpy(raidframe[i].parent_name, part->part_name, MAXDEVNAME); + else + raidframe[i].parent_name[0] = '\0'; + raidframe[i].offset = part->offset; + raidframe[i].size = label.__numBlocks; + + (*raidframe_count)++; + + return; +} + + void efi_disk_show(void) { const struct efidiskinfo *edi; + struct efi_raidframe raidframe[RAIDFRAME_NDEV]; + int raidframe_count = 0; EFI_BLOCK_IO_MEDIA *media; struct biosdisk_partition *part; uint64_t size; - int i, nparts; + int i, j, nparts; bool first; TAILQ_FOREACH(edi, &efi_disklist, list) { @@ -164,7 +237,7 @@ efi_disk_show(void) if (edi->type != BIOSDISK_TYPE_HD) continue; - if (biosdisk_readpartition(edi->dev, &part, &nparts)) + if (biosdisk_readpartition(edi->dev, 0, 0, &part, &nparts)) continue; for (i = 0; i < nparts; i++) { @@ -172,11 +245,18 @@ efi_disk_show(void) continue; if (part[i].fstype == FS_UNUSED) continue; + if (part[i].fstype == FS_RAID) { + efi_raidframe_probe(raidframe, &raidframe_count, + edi, &part[i], i); + } if (first) { printf(" "); first = false; } - printf(" hd%d%c(", edi->dev & 0x7f, i + 'a'); + if (part[i].part_name != NULL) + printf(" NAME=%s(", part[i].part_name); + else + printf(" hd%d%c(", edi->dev & 0x7f, i + 'a'); if (part[i].guid != NULL) printf("%s", part[i].guid->name); else if (part[i].fstype < FSMAXTYPES) @@ -187,7 +267,66 @@ efi_disk_show(void) } if (!first) printf("\n"); - dealloc(part, sizeof(*part) * nparts); + dealloc_biosdisk_part(part, nparts); + } + + for (i = 0; i < raidframe_count; i++) { + size_t secsize = raidframe[i].edi->bio->Media->BlockSize; + printf("raidframe raid%d serial %d in ", + raidframe[i].last_unit, raidframe[i].serial); + if (raidframe[i].parent_name[0]) + printf("NAME=%s size ", raidframe[i].parent_name); + else + printf("hd%d%c size ", + raidframe[i].edi->dev & 0x7f, + raidframe[i].parent_part + 'a'); + if (raidframe[i].size >= (10ULL * 1024 * 1024 * 1024 / secsize)) + printf("%"PRIu64" GB", + raidframe[i].size / (1024 * 1024 * 1024 / secsize)); + else + printf("%"PRIu64" MB", + raidframe[i].size / (1024 * 1024 / secsize)); + printf("\n"); + + if (biosdisk_readpartition(raidframe[i].edi->dev, + raidframe[i].offset + RF_PROTECTED_SECTORS, + raidframe[i].size, + &part, &nparts)) + continue; + + first = 1; + for (j = 0; j < nparts; j++) { + bool bootme = part[j].attr & GPT_ENT_ATTR_BOOTME; + + if (part[j].size == 0) + continue; + if (part[j].fstype == FS_UNUSED) + continue; + if (part[j].fstype == FS_RAID) /* raid in raid? */ + continue; + if (first) { + printf(" "); + first = 0; + } + if (part[j].part_name != NULL) + printf(" NAME=%s(", part[j].part_name); + else + printf(" raid%d%c(", + raidframe[i].last_unit, j + 'a'); + if (part[j].guid != NULL) + printf("%s", part[j].guid->name); + else if (part[j].fstype < FSMAXTYPES) + printf("%s", + fstypenames[part[j].fstype]); + else + printf("%d", part[j].fstype); + printf("%s)", bootme ? ", bootme" : ""); + } + + if (first == 0) + printf("\n"); + + dealloc_biosdisk_part(part, nparts); } } @@ -227,7 +366,7 @@ efidisk_get_efi_system_partition(int dev if (edi->type != BIOSDISK_TYPE_HD) return ENOTSUP; - if (biosdisk_readpartition(edi->dev, &part, &nparts)) + if (biosdisk_readpartition(edi->dev, 0, 0, &part, &nparts)) return EIO; for (i = 0; i < nparts; i++) { @@ -238,7 +377,7 @@ efidisk_get_efi_system_partition(int dev if (guid_is_equal(part[i].guid->guid, &GET_efi)) break; } - dealloc(part, sizeof(*part) * nparts); + dealloc_biosdisk_part(part, nparts); if (i == nparts) return ENOENT; Index: src/sys/arch/i386/stand/lib/Makefile diff -u src/sys/arch/i386/stand/lib/Makefile:1.45 src/sys/arch/i386/stand/lib/Makefile:1.45.8.1 --- src/sys/arch/i386/stand/lib/Makefile:1.45 Fri Feb 2 01:02:41 2018 +++ src/sys/arch/i386/stand/lib/Makefile Fri Sep 13 07:00:13 2019 @@ -1,4 +1,4 @@ -# $NetBSD: Makefile,v 1.45 2018/02/02 01:02:41 mrg Exp $ +# $NetBSD: Makefile,v 1.45.8.1 2019/09/13 07:00:13 martin Exp $ S?= ${.CURDIR}/../../../.. @@ -17,6 +17,7 @@ CPPFLAGS= -I$S/lib/libsa ${I386CPPFLAGS} #CPPFLAGS+= -DDISK_DEBUG #CPPFLAGS+= -DNO_DISKLABEL #CPPFLAGS+= -DNO_GPT +#CPPFLAGS+= -DNO_RAIDFRAME #CPPFLAGS+= -DSAVE_MEMORY SRCS= pcio.c conio.S comio.S comio_direct.c biosvideomode.S Index: src/sys/arch/i386/stand/lib/biosdisk.c diff -u src/sys/arch/i386/stand/lib/biosdisk.c:1.49 src/sys/arch/i386/stand/lib/biosdisk.c:1.49.6.1 --- src/sys/arch/i386/stand/lib/biosdisk.c:1.49 Mon Apr 2 09:44:18 2018 +++ src/sys/arch/i386/stand/lib/biosdisk.c Fri Sep 13 07:00:13 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: biosdisk.c,v 1.49 2018/04/02 09:44:18 nonaka Exp $ */ +/* $NetBSD: biosdisk.c,v 1.49.6.1 2019/09/13 07:00:13 martin Exp $ */ /* * Copyright (c) 1996, 1998 @@ -78,6 +78,7 @@ #include <sys/uuid.h> #include <fs/cd9660/iso.h> +#include <fs/unicode.h> #include <lib/libsa/saerrno.h> #include <machine/cpu.h> @@ -89,6 +90,12 @@ #include "bootinfo.h" #endif +#ifndef NO_GPT +#define MAXDEVNAME 39 /* "NAME=" + 34 char part_name */ +#else +#define MAXDEVNAME 16 +#endif + #ifndef BIOSDISK_BUFSIZE #define BIOSDISK_BUFSIZE 2048 /* must be large enough for a CD sector */ #endif @@ -104,6 +111,24 @@ struct biosdisk { #endif }; +#include <dev/raidframe/raidframevar.h> +#define RF_COMPONENT_INFO_OFFSET 16384 /* from sys/dev/raidframe/rf_netbsdkintf.c */ +#define RF_COMPONENT_LABEL_VERSION 2 /* from <dev/raidframe/rf_raid.h> */ + +#define RAIDFRAME_NDEV 16 /* abitrary limit to 15 raidframe devices */ +struct raidframe { + int last_unit; + int serial; + int biosdev; + int parent_part; +#ifndef NO_GPT + char parent_name[MAXDEVNAME + 1]; +#endif + daddr_t offset; + daddr_t size; +}; + + #ifndef NO_GPT const struct uuid GET_nbsd_raid = GPT_ENT_TYPE_NETBSD_RAIDFRAME; const struct uuid GET_nbsd_ffs = GPT_ENT_TYPE_NETBSD_FFS; @@ -111,7 +136,7 @@ const struct uuid GET_nbsd_lfs = GPT_ENT const struct uuid GET_nbsd_swap = GPT_ENT_TYPE_NETBSD_SWAP; const struct uuid GET_nbsd_ccd = GPT_ENT_TYPE_NETBSD_CCD; const struct uuid GET_nbsd_cgd = GPT_ENT_TYPE_NETBSD_CGD; -#ifdef EFIBOOT + const struct uuid GET_efi = GPT_ENT_TYPE_EFI; const struct uuid GET_mbr = GPT_ENT_TYPE_MBR; const struct uuid GET_fbsd = GPT_ENT_TYPE_FREEBSD; @@ -157,7 +182,6 @@ const struct gpt_part gpt_parts[] = { { &GET_apple_ufs, "Apple UFS" }, { &GET_bios, "BIOS Boot (GRUB)" }, }; -#endif #endif /* NO_GPT */ #ifdef _STANDALONE @@ -167,12 +191,54 @@ static struct btinfo_bootwedge bi_wedge; #define MBR_PARTS(buf) ((char *)(buf) + offsetof(struct mbr_sector, mbr_parts)) -#define RF_PROTECTED_SECTORS 64 /* XXX refer to <.../rf_optnames.h> */ - #ifndef devb2cdb #define devb2cdb(bno) (((bno) * DEV_BSIZE) / ISO_DEFAULT_BLOCK_SIZE) #endif +static void +dealloc_biosdisk(struct biosdisk *d) +{ +#ifndef NO_GPT + int i; + + for (i = 0; i < __arraycount(d->part); i++) { + if (d->part[i].part_name != NULL) + dealloc(d->part[i].part_name, BIOSDISK_PART_NAME_LEN); + } +#endif + + dealloc(d, sizeof(*d)); + + return; +} + +static struct biosdisk_partition * +copy_biosdisk_part(struct biosdisk *d) +{ + struct biosdisk_partition *part; + + part = alloc(sizeof(d->part)); + if (part == NULL) + goto out; + + memcpy(part, d->part, sizeof(d->part)); + +#ifndef NO_GPT + int i; + + for (i = 0; i < __arraycount(d->part); i++) { + if (d->part[i].part_name != NULL) { + part[i].part_name = alloc(BIOSDISK_PART_NAME_LEN); + memcpy(part[i].part_name, d->part[i].part_name, + BIOSDISK_PART_NAME_LEN); + } + } +#endif + +out: + return part; +} + int biosdisk_strategy(void *devdata, int flag, daddr_t dblk, size_t size, void *buf, size_t *rsize) @@ -228,7 +294,7 @@ alloc_biosdisk(int biosdev) #ifdef DISK_DEBUG printf("no geometry information\n"); #endif - dealloc(d, sizeof(*d)); + dealloc_biosdisk(d); return NULL; } return d; @@ -262,8 +328,33 @@ guid_is_equal(const struct uuid *a, cons return (memcmp(a, b, sizeof(*a)) == 0 ? true : false); } +#ifndef NO_GPT +static void +part_name_utf8(const uint16_t *utf16_src, size_t utf16_srclen, + char *utf8_dst, size_t utf8_dstlen) +{ + char *c = utf8_dst; + size_t r = utf8_dstlen - 1; + size_t n; + int j; + + if (utf8_dst == NULL) + return; + + for (j = 0; j < utf16_srclen && utf16_src[j] != 0x0000; j++) { + n = wput_utf8(c, r, le16toh(utf16_src[j])); + if (n == 0) + break; + c += n; r -= n; + } + *c = '\0'; + + return; +} +#endif + static int -check_gpt(struct biosdisk *d, daddr_t sector) +check_gpt(struct biosdisk *d, daddr_t rf_offset, daddr_t sector) { struct gpt_hdr gpth; const struct gpt_ent *ep; @@ -296,7 +387,7 @@ check_gpt(struct biosdisk *d, daddr_t se return -1; } - if (gpth.hdr_lba_self != sector) + if (gpth.hdr_lba_self + rf_offset != sector) return -1; #ifdef _STANDALONE @@ -308,7 +399,7 @@ check_gpt(struct biosdisk *d, daddr_t se sectors = sizeof(d->buf)/d->ll.secsize; /* sectors per buffer */ entries = sizeof(d->buf)/gpth.hdr_entsz; /* entries per buffer */ - entblk = gpth.hdr_lba_table; + entblk = gpth.hdr_lba_table + rf_offset; crc = crc32(0, NULL, 0); j = 0; @@ -344,7 +435,7 @@ check_gpt(struct biosdisk *d, daddr_t se d->part[j].fstype = FS_CGD; else d->part[j].fstype = FS_OTHER; -#ifdef EFIBOOT +#ifndef NO_GPT for (int k = 0; k < __arraycount(gpt_parts); k++) { @@ -352,6 +443,13 @@ check_gpt(struct biosdisk *d, daddr_t se d->part[j].guid = &gpt_parts[k]; } d->part[j].attr = ep[i].ent_attr; + + d->part[j].part_name = + alloc(BIOSDISK_PART_NAME_LEN); + part_name_utf8(ep[i].ent_name, + sizeof(ep[i].ent_name), + d->part[j].part_name, + BIOSDISK_PART_NAME_LEN); #endif j++; } @@ -370,7 +468,7 @@ check_gpt(struct biosdisk *d, daddr_t se } static int -read_gpt(struct biosdisk *d) +read_gpt(struct biosdisk *d, daddr_t rf_offset, daddr_t rf_size) { struct biosdisk_extinfo ed; daddr_t gptsector[2]; @@ -380,23 +478,30 @@ read_gpt(struct biosdisk *d) /* No GPT on floppy and CD */ return -1; - gptsector[0] = GPT_HDR_BLKNO; - if (set_geometry(&d->ll, &ed) == 0 && d->ll.flags & BIOSDISK_INT13EXT) { - gptsector[1] = ed.totsec - 1; - /* Sanity check values returned from BIOS */ - if (ed.sbytes >= 512 && (ed.sbytes & (ed.sbytes - 1)) == 0) - d->ll.secsize = ed.sbytes; + if (rf_offset && rf_size) { + gptsector[0] = rf_offset + GPT_HDR_BLKNO; + gptsector[1] = rf_offset + rf_size - 1; } else { + gptsector[0] = GPT_HDR_BLKNO; + if (set_geometry(&d->ll, &ed) == 0 && + d->ll.flags & BIOSDISK_INT13EXT) { + gptsector[1] = ed.totsec - 1; + /* Sanity check values returned from BIOS */ + if (ed.sbytes >= 512 && + (ed.sbytes & (ed.sbytes - 1)) == 0) + d->ll.secsize = ed.sbytes; + } else { #ifdef DISK_DEBUG - printf("Unable to determine extended disk geometry - " - "using CHS\n"); + printf("Unable to determine extended disk geometry - " + "using CHS\n"); #endif - /* at least try some other reasonable values then */ - gptsector[1] = d->ll.chs_sectors - 1; + /* at least try some other reasonable values then */ + gptsector[1] = d->ll.chs_sectors - 1; + } } for (i = 0; i < __arraycount(gptsector); i++) { - error = check_gpt(d, gptsector[i]); + error = check_gpt(d, rf_offset, gptsector[i]); if (error == 0) break; } @@ -546,7 +651,7 @@ check_cd9660(struct biosdisk *d) #endif static int -read_label(struct biosdisk *d) +read_label(struct biosdisk *d, daddr_t offset) { struct disklabel dflt_lbl; struct mbr_partition mbr[MBR_PART_COUNT]; @@ -573,11 +678,11 @@ read_label(struct biosdisk *d) * find NetBSD Partition in DOS partition table * XXX check magic??? */ - ext_base = 0; - next_ext = 0; + ext_base = offset; + next_ext = offset; for (;;) { this_ext = ext_base + next_ext; - next_ext = 0; + next_ext = offset; if (readsects(&d->ll, this_ext, 1, d->buf, 0)) { #ifdef DISK_DEBUG printf("error reading MBR sector %u\n", this_ext); @@ -607,14 +712,14 @@ read_label(struct biosdisk *d) return error; } if (MBR_IS_EXTENDED(typ)) { - next_ext = mbr[i].mbrp_start; + next_ext = mbr[i].mbrp_start + offset; continue; } #ifdef COMPAT_386BSD_MBRPART - if (this_ext == 0 && typ == MBR_PTYPE_386BSD) + if (this_ext == offset && typ == MBR_PTYPE_386BSD) sector_386bsd = sector; #endif - if (this_ext != 0) { + if (this_ext != offset) { if (dflt_lbl.d_npartitions >= MAXPARTITIONS) continue; p = &dflt_lbl.d_partitions[dflt_lbl.d_npartitions++]; @@ -624,15 +729,15 @@ read_label(struct biosdisk *d) p->p_size = mbr[i].mbrp_size; p->p_fstype = xlat_mbr_fstype(typ); } - if (next_ext == 0) + if (next_ext == offset) break; - if (ext_base == 0) { + if (ext_base == offset) { ext_base = next_ext; - next_ext = 0; + next_ext = offset; } } - sector = 0; + sector = offset; #ifdef COMPAT_386BSD_MBRPART if (sector_386bsd != -1) { printf("old BSD partition ID!\n"); @@ -671,31 +776,74 @@ read_label(struct biosdisk *d) #if !defined(NO_DISKLABEL) || !defined(NO_GPT) static int -read_partitions(struct biosdisk *d) +read_partitions(struct biosdisk *d, daddr_t offset, daddr_t size) { int error; error = -1; #ifndef NO_GPT - error = read_gpt(d); + error = read_gpt(d, offset, size); if (error == 0) return 0; #endif #ifndef NO_DISKLABEL - error = read_label(d); + error = read_label(d, offset); #endif return error; } #endif +#ifndef NO_RAIDFRAME +static void +raidframe_probe(struct raidframe *raidframe, int *raidframe_count, + struct biosdisk *d, int part) +{ + int i = *raidframe_count; + struct RF_ComponentLabel_s label; + daddr_t offset; + + if (i + 1 > RAIDFRAME_NDEV) + return; + + offset = d->part[part].offset; + if ((biosdisk_read_raidframe(d->ll.dev, offset, &label)) != 0) + return; + + if (label.version != RF_COMPONENT_LABEL_VERSION) + printf("Unexpected raidframe label version\n"); + + raidframe[i].last_unit = label.last_unit; + raidframe[i].serial = label.serial_number; + raidframe[i].biosdev = d->ll.dev; + raidframe[i].parent_part = part; +#ifndef NO_GPT + if (d->part[part].part_name) + strlcpy(raidframe[i].parent_name, + d->part[part].part_name, MAXDEVNAME); + else + raidframe[i].parent_name[0] = '\0'; +#endif + raidframe[i].offset = offset; + raidframe[i].size = label.__numBlocks; + + (*raidframe_count)++; + + return; +} +#endif + void biosdisk_probe(void) { - struct biosdisk d; + struct biosdisk *d; struct biosdisk_extinfo ed; +#ifndef NO_RAIDFRAME + struct raidframe raidframe[RAIDFRAME_NDEV]; + int raidframe_count = 0; +#endif uint64_t size; int first; int i; @@ -705,26 +853,31 @@ biosdisk_probe(void) for (i = 0; i < MAX_BIOSDISKS + 2; i++) { first = 1; - memset(&d, 0, sizeof(d)); + d = alloc(sizeof(*d)); + if (d == NULL) { + printf("Out of memory\n"); + return; + } + memset(d, 0, sizeof(*d)); memset(&ed, 0, sizeof(ed)); if (i >= MAX_BIOSDISKS) - d.ll.dev = 0x00 + i - MAX_BIOSDISKS; /* fd */ + d->ll.dev = 0x00 + i - MAX_BIOSDISKS; /* fd */ else - d.ll.dev = 0x80 + i; /* hd/cd */ - if (set_geometry(&d.ll, &ed)) - continue; + d->ll.dev = 0x80 + i; /* hd/cd */ + if (set_geometry(&d->ll, &ed)) + goto next_disk; printf("disk "); - switch (d.ll.type) { + switch (d->ll.type) { case BIOSDISK_TYPE_CD: printf("cd0\n cd0a\n"); break; case BIOSDISK_TYPE_FD: - printf("fd%d\n", d.ll.dev & 0x7f); - printf(" fd%da\n", d.ll.dev & 0x7f); + printf("fd%d\n", d->ll.dev & 0x7f); + printf(" fd%da\n", d->ll.dev & 0x7f); break; case BIOSDISK_TYPE_HD: - printf("hd%d", d.ll.dev & 0x7f); - if (d.ll.flags & BIOSDISK_INT13EXT) { + printf("hd%d", d->ll.dev & 0x7f); + if (d->ll.flags & BIOSDISK_INT13EXT) { printf(" size "); size = ed.totsec * ed.sbytes; if (size >= (10ULL * 1024 * 1024 * 1024)) @@ -738,38 +891,132 @@ biosdisk_probe(void) break; } #if !defined(NO_DISKLABEL) || !defined(NO_GPT) - if (d.ll.type != BIOSDISK_TYPE_HD) - continue; + if (d->ll.type != BIOSDISK_TYPE_HD) + goto next_disk; - if (read_partitions(&d) != 0) - continue; + if (read_partitions(d, 0, 0) != 0) + goto next_disk; for (part = 0; part < BIOSDISKNPART; part++) { - if (d.part[part].size == 0) + if (d->part[part].size == 0) continue; - if (d.part[part].fstype == FS_UNUSED) + if (d->part[part].fstype == FS_UNUSED) continue; +#ifndef NO_RAIDFRAME + if (d->part[part].fstype == FS_RAID) + raidframe_probe(raidframe, + &raidframe_count, d, part); +#endif if (first) { printf(" "); first = 0; } - printf(" hd%d%c(", d.ll.dev & 0x7f, part + 'a'); -#ifdef EFIBOOT - if (d.part[part].guid != NULL) - printf("%s", d.part[part].guid->name); +#ifndef NO_GPT + if (d->part[part].part_name != NULL) + printf(" NAME=%s(", d->part[part].part_name); + else +#endif + printf(" hd%d%c(", d->ll.dev & 0x7f, part + 'a'); + +#ifndef NO_GPT + if (d->part[part].guid != NULL) + printf("%s", d->part[part].guid->name); else #endif - if (d.part[part].fstype < FSMAXTYPES) + + if (d->part[part].fstype < FSMAXTYPES) printf("%s", - fstypenames[d.part[part].fstype]); + fstypenames[d->part[part].fstype]); else - printf("%d", d.part[part].fstype); + printf("%d", d->part[part].fstype); printf(")"); } #endif if (first == 0) printf("\n"); + +next_disk: + dealloc_biosdisk(d); } + +#ifndef NO_RAIDFRAME + for (i = 0; i < raidframe_count; i++) { + size_t secsize; + + if ((d = alloc_biosdisk(raidframe[i].biosdev)) == NULL) { + printf("Out of memory\n"); + return; + } + + secsize = d->ll.secsize; + + printf("raidframe raid%d serial %d in ", + raidframe[i].last_unit, raidframe[i].serial); +#ifndef NO_GPT + if (raidframe[i].parent_name[0]) + printf("NAME=%s size ", raidframe[i].parent_name); + else +#endif + printf("hd%d%c size ", d->ll.dev & 0x7f, + raidframe[i].parent_part + 'a'); + if (raidframe[i].size >= (10ULL * 1024 * 1024 * 1024 / secsize)) + printf("%"PRIu64" GB", + raidframe[i].size / (1024 * 1024 * 1024 / secsize)); + else + printf("%"PRIu64" MB", + raidframe[i].size / (1024 * 1024 / secsize)); + printf("\n"); + + if (read_partitions(d, + raidframe[i].offset + RF_PROTECTED_SECTORS, + raidframe[i].size) != 0) + goto next_raidrame; + + first = 1; + for (part = 0; part < BIOSDISKNPART; part++) { +#ifndef NO_GPT + bool bootme = d->part[part].attr & GPT_ENT_ATTR_BOOTME; +#else + bool bootme = 0; +#endif + + if (d->part[part].size == 0) + continue; + if (d->part[part].fstype == FS_UNUSED) + continue; + if (d->part[part].fstype == FS_RAID) + continue; + if (first) { + printf(" "); + first = 0; + } +#ifndef NO_GPT + if (d->part[part].part_name != NULL) + printf(" NAME=%s(", d->part[part].part_name); + else +#endif + printf(" raid%d%c(", raidframe[i].last_unit, + part + 'a'); +#ifndef NO_GPT + if (d->part[part].guid != NULL) + printf("%s", d->part[part].guid->name); + else +#endif + if (d->part[part].fstype < FSMAXTYPES) + printf("%s", + fstypenames[d->part[part].fstype]); + else + printf("%d", d->part[part].fstype); + printf("%s)", bootme ? ", bootme" : ""); + } + +next_raidrame: + if (first == 0) + printf("\n"); + + dealloc_biosdisk(d); + } +#endif } /* Determine likely partition for possible sector number of dos @@ -777,68 +1024,97 @@ biosdisk_probe(void) */ int -biosdisk_findpartition(int biosdev, daddr_t sector) +biosdisk_findpartition(int biosdev, daddr_t sector, + int *partition, const char **part_name) { #if defined(NO_DISKLABEL) && defined(NO_GPT) + *partition = 0; + *part_name = NULL; return 0; #else + int i; struct biosdisk *d; - int partition = 0; -#ifdef EFIBOOT - int candidate = 0; + int biosboot_sector_part = -1; + int bootable_fs_part = -1; + int boot_part = 0; +#ifndef NO_GPT + int gpt_bootme_part = -1; + static char namebuf[MAXDEVNAME + 1]; #endif #ifdef DISK_DEBUG printf("looking for partition device %x, sector %"PRId64"\n", biosdev, sector); #endif + /* default ot first partition */ + *partition = 0; + *part_name = NULL; + /* Look for netbsd partition that is the dos boot one */ d = alloc_biosdisk(biosdev); if (d == NULL) - return 0; + return -1; - if (read_partitions(d) == 0) { - for (partition = (BIOSDISKNPART-1); --partition;) { - if (d->part[partition].fstype == FS_UNUSED) + if (read_partitions(d, 0, 0) == 0) { + for (i = 0; i < BIOSDISKNPART; i++) { + if (d->part[i].fstype == FS_UNUSED) continue; -#ifdef EFIBOOT - switch (d->part[partition].fstype) { + + if (d->part[i].offset == sector && + biosboot_sector_part == -1) + biosboot_sector_part = i; + +#ifndef NO_GPT + if (d->part[i].attr & GPT_ENT_ATTR_BOOTME && + gpt_bootme_part == -1) + gpt_bootme_part = i; +#endif + switch (d->part[i].fstype) { case FS_BSDFFS: case FS_BSDLFS: case FS_RAID: case FS_CCD: case FS_CGD: case FS_ISO9660: - if (d->part[partition].attr & GPT_ENT_ATTR_BOOTME) - goto found; - candidate = partition; + if (bootable_fs_part == -1) + bootable_fs_part = i; break; default: - if (d->part[partition].attr & GPT_ENT_ATTR_BOOTME) - candidate = partition; break; } -#else - if (d->part[partition].offset == sector) - break; + } + +#ifndef NO_GPT + if (gpt_bootme_part != -1) + boot_part = gpt_bootme_part; + else #endif + if (biosboot_sector_part != -1) + boot_part = biosboot_sector_part; + else if (bootable_fs_part != -1) + boot_part = bootable_fs_part; + else + boot_part = 0; + + *partition = boot_part; +#ifndef NO_GPT + if (part_name && d->part[boot_part].part_name) { + strlcpy(namebuf, d->part[boot_part].part_name, + BIOSDISK_PART_NAME_LEN); + *part_name = namebuf; } -#ifdef EFIBOOT -found: - if (partition == 0 && candidate != 0) - partition = candidate; #endif } - dealloc(d, sizeof(*d)); - return partition; + dealloc_biosdisk(d); + return 0; #endif /* NO_DISKLABEL && NO_GPT */ } int -biosdisk_readpartition(int biosdev, struct biosdisk_partition **partpp, - int *rnum) +biosdisk_readpartition(int biosdev, daddr_t offset, daddr_t size, + struct biosdisk_partition **partpp, int *rnum) { #if defined(NO_DISKLABEL) && defined(NO_GPT) return ENOTSUP; @@ -852,27 +1128,70 @@ biosdisk_readpartition(int biosdev, stru if (d == NULL) return ENOMEM; - if (read_partitions(d)) { + if (read_partitions(d, offset, size)) { rv = EINVAL; goto out; } - part = alloc(sizeof(d->part)); + part = copy_biosdisk_part(d); if (part == NULL) { rv = ENOMEM; goto out; } - memcpy(part, d->part, sizeof(d->part)); *partpp = part; *rnum = (int)__arraycount(d->part); rv = 0; out: - dealloc(d, sizeof(*d)); + dealloc_biosdisk(d); return rv; #endif /* NO_DISKLABEL && NO_GPT */ } +#ifndef NO_RAIDFRAME +int +biosdisk_read_raidframe(int biosdev, daddr_t offset, + struct RF_ComponentLabel_s *label) +{ +#if defined(NO_DISKLABEL) && defined(NO_GPT) + return ENOTSUP; +#else + struct biosdisk *d; + struct biosdisk_extinfo ed; + daddr_t size; + int rv = -1; + + /* Look for netbsd partition that is the dos boot one */ + d = alloc_biosdisk(biosdev); + if (d == NULL) + goto out; + + if (d->ll.type != BIOSDISK_TYPE_HD) + /* No raidframe on floppy and CD */ + goto out; + + if (set_geometry(&d->ll, &ed) != 0) + goto out; + + /* Sanity check values returned from BIOS */ + if (ed.sbytes >= 512 && + (ed.sbytes & (ed.sbytes - 1)) == 0) + d->ll.secsize = ed.sbytes; + + offset += (RF_COMPONENT_INFO_OFFSET / d->ll.secsize); + size = roundup(sizeof(*label), d->ll.secsize) / d->ll.secsize; + if (readsects(&d->ll, offset, size, d->buf, 0)) + goto out; + memcpy(label, d->buf, sizeof(*label)); + rv = 0; +out: + if (d != NULL) + dealloc_biosdisk(d); + return rv; +#endif /* NO_DISKLABEL && NO_GPT */ +} +#endif /* NO_RAIDFRAME */ + #ifdef _STANDALONE static void add_biosdisk_bootinfo(void) @@ -886,6 +1205,39 @@ add_biosdisk_bootinfo(void) } #endif +#ifndef NO_GPT +static daddr_t +raidframe_part_offset(struct biosdisk *d, int part) +{ + struct biosdisk raidframe; + daddr_t rf_offset; + daddr_t rf_size; + int i, candidate; + + memset(&raidframe, 0, sizeof(raidframe)); + raidframe.ll = d->ll; + + rf_offset = d->part[part].offset + RF_PROTECTED_SECTORS; + rf_size = d->part[part].size; + if (read_gpt(&raidframe, rf_offset, rf_size) != 0) + return RF_PROTECTED_SECTORS; + + candidate = 0; + for (i = 0; i < BIOSDISKNPART; i++) { + if (raidframe.part[i].size == 0) + continue; + if (raidframe.part[i].fstype == FS_UNUSED) + continue; +#ifndef NO_GPT + if (raidframe.part[i].attr & GPT_ENT_ATTR_BOOTME) + candidate = i; +#endif + } + + return RF_PROTECTED_SECTORS + raidframe.part[candidate].offset; +} +#endif + int biosdisk_open(struct open_file *f, ...) /* struct open_file *f, int biosdev, int partition */ @@ -915,7 +1267,7 @@ biosdisk_open(struct open_file *f, ...) #endif #if !defined(NO_DISKLABEL) || !defined(NO_GPT) - error = read_partitions(d); + error = read_partitions(d, 0, 0); if (error == -1) { error = 0; goto nolabel; @@ -935,7 +1287,11 @@ biosdisk_open(struct open_file *f, ...) d->boff = d->part[partition].offset; if (d->part[partition].fstype == FS_RAID) +#ifndef NO_GPT + d->boff += raidframe_part_offset(d, partition); +#else d->boff += RF_PROTECTED_SECTORS; +#endif #ifdef _STANDALONE bi_wedge.startblk = d->part[partition].offset; @@ -956,10 +1312,327 @@ nolabel: out: va_end(ap); if (error) - dealloc(d, sizeof(*d)); + dealloc_biosdisk(d); + return error; +} + +#ifndef NO_GPT +static int +biosdisk_find_name(const char *fname, int *biosdev, + daddr_t *offset, daddr_t *size) +{ + struct biosdisk *d; + char name[MAXDEVNAME + 1]; + char *sep; +#ifndef NO_RAIDFRAME + struct raidframe raidframe[RAIDFRAME_NDEV]; + int raidframe_count = 0; +#endif + int i; + int part; + int ret = -1; + + /* Strip leadinf NAME= and cut after the coloon included */ + strlcpy(name, fname + 5, MAXDEVNAME); + sep = strchr(name, ':'); + if (sep) + *sep = '\0'; + + for (i = 0; i < MAX_BIOSDISKS; i++) { + d = alloc(sizeof(*d)); + if (d == NULL) { + printf("Out of memory\n"); + goto out; + } + + memset(d, 0, sizeof(*d)); + d->ll.dev = 0x80 + i; /* hd/cd */ + if (set_geometry(&d->ll, NULL)) + goto next_disk; + + if (d->ll.type != BIOSDISK_TYPE_HD) + goto next_disk; + + if (read_partitions(d, 0, 0) != 0) + goto next_disk; + + for (part = 0; part < BIOSDISKNPART; part++) { + if (d->part[part].size == 0) + continue; + if (d->part[part].fstype == FS_UNUSED) + continue; +#ifndef NO_RAIDFRAME + if (d->part[part].fstype == FS_RAID) { + raidframe_probe(raidframe, + &raidframe_count, d, part); + /* + * Do not match RAID partition for a name, + * we want to report an inner partition. + */ + continue; + } +#endif + if (d->part[part].part_name != NULL && + strcmp(d->part[part].part_name, name) == 0) { + *biosdev = d->ll.dev; + *offset = d->part[part].offset; + *size = d->part[part].size; + ret = 0; + goto out; + } + + } +next_disk: + dealloc_biosdisk(d); + d = NULL; + } + +#ifndef NO_RAIDFRAME + for (i = 0; i < raidframe_count; i++) { + int candidate = -1; + + if ((d = alloc_biosdisk(raidframe[i].biosdev)) == NULL) { + printf("Out of memory\n"); + goto out; + } + + if (read_partitions(d, + raidframe[i].offset + RF_PROTECTED_SECTORS, + raidframe[i].size) != 0) + goto next_raidframe; + + for (part = 0; part < BIOSDISKNPART; part++) { + bool bootme = d->part[part].attr & GPT_ENT_ATTR_BOOTME; + if (d->part[part].size == 0) + continue; + if (d->part[part].fstype == FS_UNUSED) + continue; + if (d->part[part].part_name == NULL) + continue; + if (strcmp(d->part[part].part_name, name) == 0) { + *biosdev = raidframe[i].biosdev; + *offset = raidframe[i].offset + + RF_PROTECTED_SECTORS + + d->part[part].offset; + *size = d->part[part].size; + ret = 0; + goto out; + } + if (strcmp(raidframe[i].parent_name, name) == 0) { + if (candidate == -1 || bootme) + candidate = part; + continue; + } + } + + if (candidate != -1) { + *biosdev = raidframe[i].biosdev; + *offset = raidframe[i].offset + + RF_PROTECTED_SECTORS + + d->part[candidate].offset; + *size = d->part[candidate].size; + ret = 0; + goto out; + } + +next_raidframe: + dealloc_biosdisk(d); + d = NULL; + } +#endif + +out: + if (d != NULL) + dealloc_biosdisk(d); + + return ret; +} +#endif + +#ifndef NO_RAIDFRAME +static int +biosdisk_find_raid(const char *name, int *biosdev, + daddr_t *offset, daddr_t *size) +{ + struct biosdisk *d = NULL; + struct raidframe raidframe[RAIDFRAME_NDEV]; + int raidframe_count = 0; + int i; + int target_unit = 0; + int target_part; + int part; + int ret = -1; + + if (strstr(name, "raid") != name) + goto out; + +#define isnum(c) ((c) >= '0' && (c) <= '9') + i = 4; /* skip leading "raid" */ + if (!isnum(name[i])) + goto out; + do { + target_unit *= 10; + target_unit += name[i++] - '0'; + } while (isnum(name[i])); + +#define isvalidpart(c) ((c) >= 'a' && (c) <= 'z') + + if (!isvalidpart(name[i])) + goto out; + target_part = name[i] - 'a'; + + for (i = 0; i < MAX_BIOSDISKS; i++) { + d = alloc(sizeof(*d)); + if (d == NULL) { + printf("Out of memory\n"); + goto out; + } + + memset(d, 0, sizeof(*d)); + d->ll.dev = 0x80 + i; /* hd/cd */ + if (set_geometry(&d->ll, NULL)) + goto next_disk; + + if (d->ll.type != BIOSDISK_TYPE_HD) + goto next_disk; + + if (read_partitions(d, 0, 0) != 0) + goto next_disk; + + for (part = 0; part < BIOSDISKNPART; part++) { + if (d->part[part].size == 0) + continue; + if (d->part[part].fstype != FS_RAID) + continue; + raidframe_probe(raidframe, + &raidframe_count, d, part); + + } +next_disk: + dealloc_biosdisk(d); + d = NULL; + } + + for (i = 0; i < raidframe_count; i++) { + if (raidframe[i].last_unit != target_unit) + continue; + + if ((d = alloc_biosdisk(raidframe[i].biosdev)) == NULL) { + printf("Out of memory\n"); + goto out; + } + + if (read_partitions(d, + raidframe[i].offset + RF_PROTECTED_SECTORS, + raidframe[i].size) != 0) + goto next_raidframe; + + for (part = 0; part < BIOSDISKNPART; part++) { + if (d->part[part].size == 0) + continue; + if (d->part[part].fstype == FS_UNUSED) + continue; + if (part == target_part) { + *biosdev = raidframe[i].biosdev; + *offset = raidframe[i].offset + + RF_PROTECTED_SECTORS + + d->part[part].offset; + *size = d->part[part].size; + ret = 0; + goto out; + } + } +next_raidframe: + dealloc_biosdisk(d); + d = NULL; + } +out: + if (d != NULL) + dealloc_biosdisk(d); + + return ret; +} +#endif + +int +biosdisk_open_name(struct open_file *f, const char *name) +{ +#if defined(NO_GPT) && defined(NO_RAIDFRAME) + return ENXIO; +#else + struct biosdisk *d = NULL; + int biosdev; + daddr_t offset; + daddr_t size; + int error = -1; + +#ifndef NO_GPT + if (strstr(name, "NAME=") == name) + error = biosdisk_find_name(name, &biosdev, &offset, &size); +#endif +#ifndef NO_RAIDFRAME + if (strstr(name, "raid") == name) + error = biosdisk_find_raid(name, &biosdev, &offset, &size); +#endif + + if (error != 0) { + printf("%s not found\n", name); + error = ENXIO; + goto out; + } + + d = alloc_biosdisk(biosdev); + if (d == NULL) { + error = ENXIO; + goto out; + } + +#ifdef _STANDALONE + bi_disk.biosdev = d->ll.dev; + bi_disk.partition = 0; + bi_disk.labelsector = -1; + + bi_wedge.biosdev = d->ll.dev; + + /* + * If we did not get wedge match info from check_gpt() + * compute it now. + */ + if (bi_wedge.matchblk == -1) { + if (readsects(&d->ll, offset, 1, d->buf, 1)) { +#ifdef DISK_DEBUG + printf("Error reading sector at %"PRId64"\n", offset); +#endif + error = EIO; + goto out; + } + + bi_wedge.matchblk = offset; + bi_wedge.matchnblks = 1; + + md5(bi_wedge.matchhash, d->buf, d->ll.secsize); + } +#endif + + d->boff = offset; + +#ifdef _STANDALONE + bi_wedge.startblk = offset; + bi_wedge.nblks = size; + + add_biosdisk_bootinfo(); +#endif + + f->f_devdata = d; +out: + if (error && d != NULL) + dealloc_biosdisk(d); return error; +#endif } + + #ifndef LIBSA_NO_FS_CLOSE int biosdisk_close(struct open_file *f) @@ -970,7 +1643,7 @@ biosdisk_close(struct open_file *f) if (d->ll.type == BIOSDISK_TYPE_FD) wait_sec(3); /* 2s is enough on all PCs I found */ - dealloc(d, sizeof(*d)); + dealloc_biosdisk(d); f->f_devdata = NULL; return 0; } Index: src/sys/arch/i386/stand/lib/biosdisk.h diff -u src/sys/arch/i386/stand/lib/biosdisk.h:1.10 src/sys/arch/i386/stand/lib/biosdisk.h:1.10.6.1 --- src/sys/arch/i386/stand/lib/biosdisk.h:1.10 Mon Apr 2 09:44:18 2018 +++ src/sys/arch/i386/stand/lib/biosdisk.h Fri Sep 13 07:00:13 2019 @@ -1,4 +1,4 @@ -/* $NetBSD: biosdisk.h,v 1.10 2018/04/02 09:44:18 nonaka Exp $ */ +/* $NetBSD: biosdisk.h,v 1.10.6.1 2019/09/13 07:00:13 martin Exp $ */ /* * Copyright (c) 1996 @@ -25,25 +25,33 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define BIOSDISK_PART_NAME_LEN 36 + struct biosdisk_partition { daddr_t offset; daddr_t size; int fstype; -#ifdef EFIBOOT +#ifndef NO_GPT const struct gpt_part { const struct uuid *guid; const char *name; } *guid; uint64_t attr; + char *part_name; /* maximum BIOSDISK_PART_NAME_LEN */ #endif }; int biosdisk_strategy(void *, int, daddr_t, size_t, void *, size_t *); int biosdisk_open(struct open_file *, ...); +int biosdisk_open_name(struct open_file *, const char *); int biosdisk_close(struct open_file *); int biosdisk_ioctl(struct open_file *, u_long, void *); -int biosdisk_findpartition(int, daddr_t); -int biosdisk_readpartition(int, struct biosdisk_partition **, int *); +int biosdisk_findpartition(int, daddr_t, int *, const char **); +int biosdisk_readpartition(int, daddr_t, daddr_t, + struct biosdisk_partition **, int *); + +struct RF_ComponentLabel_s; +int biosdisk_read_raidframe(int, daddr_t, struct RF_ComponentLabel_s *); #if !defined(NO_GPT) struct uuid;