1*f4f4f64eSjsg /* $OpenBSD: efidev.c,v 1.42 2023/10/26 14:08:48 jsg Exp $ */
27b5f1cbeSyasuoka
37b5f1cbeSyasuoka /*
47b5f1cbeSyasuoka * Copyright (c) 1996 Michael Shalayeff
57b5f1cbeSyasuoka * Copyright (c) 2003 Tobias Weingartner
629265824Syasuoka * Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
77b5f1cbeSyasuoka * All rights reserved.
87b5f1cbeSyasuoka *
97b5f1cbeSyasuoka * Redistribution and use in source and binary forms, with or without
107b5f1cbeSyasuoka * modification, are permitted provided that the following conditions
117b5f1cbeSyasuoka * are met:
127b5f1cbeSyasuoka * 1. Redistributions of source code must retain the above copyright
137b5f1cbeSyasuoka * notice, this list of conditions and the following disclaimer.
147b5f1cbeSyasuoka * 2. Redistributions in binary form must reproduce the above copyright
157b5f1cbeSyasuoka * notice, this list of conditions and the following disclaimer in the
167b5f1cbeSyasuoka * documentation and/or other materials provided with the distribution.
177b5f1cbeSyasuoka *
187b5f1cbeSyasuoka * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
197b5f1cbeSyasuoka * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
207b5f1cbeSyasuoka * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
217b5f1cbeSyasuoka * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
227b5f1cbeSyasuoka * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
237b5f1cbeSyasuoka * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
247b5f1cbeSyasuoka * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
257b5f1cbeSyasuoka * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
267b5f1cbeSyasuoka * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
277b5f1cbeSyasuoka * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
287b5f1cbeSyasuoka * SUCH DAMAGE.
297b5f1cbeSyasuoka *
307b5f1cbeSyasuoka */
317b5f1cbeSyasuoka #include <sys/param.h>
327b5f1cbeSyasuoka #include <sys/reboot.h>
337b5f1cbeSyasuoka #include <sys/disklabel.h>
3478160737Syasuoka #include <lib/libz/zlib.h>
35055ff051Syasuoka #include <isofs/cd9660/iso.h>
367b5f1cbeSyasuoka
377b5f1cbeSyasuoka #include "libsa.h"
387b5f1cbeSyasuoka #include "disk.h"
397b5f1cbeSyasuoka
407b5f1cbeSyasuoka #ifdef SOFTRAID
417b5f1cbeSyasuoka #include <dev/softraidvar.h>
42e876def9Sjsing #include <lib/libsa/softraid.h>
4365f4a3c7Sjsing #include "softraid_amd64.h"
447b5f1cbeSyasuoka #endif
457b5f1cbeSyasuoka
467b5f1cbeSyasuoka #include <efi.h>
477b5f1cbeSyasuoka
487b5f1cbeSyasuoka extern int debug;
496e6a01b2Skrw extern EFI_BOOT_SERVICES *BS;
507b5f1cbeSyasuoka
517b5f1cbeSyasuoka #include "efidev.h"
527b5f1cbeSyasuoka #include "biosdev.h" /* for dklookup() */
537b5f1cbeSyasuoka
547b5f1cbeSyasuoka #define EFI_BLKSPERSEC(_ed) ((_ed)->blkio->Media->BlockSize / DEV_BSIZE)
557b5f1cbeSyasuoka #define EFI_SECTOBLK(_ed, _n) ((_n) * EFI_BLKSPERSEC(_ed))
567b5f1cbeSyasuoka
577b5f1cbeSyasuoka struct efi_diskinfo {
587b5f1cbeSyasuoka EFI_BLOCK_IO *blkio;
597b5f1cbeSyasuoka UINT32 mediaid;
607b5f1cbeSyasuoka };
617b5f1cbeSyasuoka
627b5f1cbeSyasuoka int bios_bootdev;
637b5f1cbeSyasuoka static EFI_STATUS
647b5f1cbeSyasuoka efid_io(int, efi_diskinfo_t, u_int, int, void *);
657b5f1cbeSyasuoka static int efid_diskio(int, struct diskinfo *, u_int, int, void *);
66055ff051Syasuoka static int efi_getdisklabel_cd9660(efi_diskinfo_t, struct disklabel *);
677b5f1cbeSyasuoka static u_int findopenbsd(efi_diskinfo_t, const char **);
680fe25aa9Skrw static u_int findopenbsd_gpt(efi_diskinfo_t, const char **);
6912b4e828Skrw static int gpt_chk_mbr(struct dos_partition *, u_int64_t);
707b5f1cbeSyasuoka
717b5f1cbeSyasuoka void
efid_init(struct diskinfo * dip,void * handle)727b5f1cbeSyasuoka efid_init(struct diskinfo *dip, void *handle)
737b5f1cbeSyasuoka {
747b5f1cbeSyasuoka EFI_BLOCK_IO *blkio = handle;
757b5f1cbeSyasuoka
767b5f1cbeSyasuoka memset(dip, 0, sizeof(struct diskinfo));
777b5f1cbeSyasuoka dip->efi_info = alloc(sizeof(struct efi_diskinfo));
787b5f1cbeSyasuoka dip->efi_info->blkio = blkio;
797b5f1cbeSyasuoka dip->efi_info->mediaid = blkio->Media->MediaId;
807b5f1cbeSyasuoka dip->diskio = efid_diskio;
817b5f1cbeSyasuoka dip->strategy = efistrategy;
827b5f1cbeSyasuoka }
837b5f1cbeSyasuoka
847b5f1cbeSyasuoka static EFI_STATUS
efid_io(int rw,efi_diskinfo_t ed,u_int off,int nsect,void * buf)857b5f1cbeSyasuoka efid_io(int rw, efi_diskinfo_t ed, u_int off, int nsect, void *buf)
867b5f1cbeSyasuoka {
876202161eSyasuoka u_int blks, start, end;
886e6a01b2Skrw EFI_PHYSICAL_ADDRESS addr;
895eca72b4Skrw EFI_STATUS status;
905eca72b4Skrw caddr_t data;
915eca72b4Skrw size_t size;
927b5f1cbeSyasuoka
93fb41e152Skrw /* block count of the intrinsic block size in DEV_BSIZE */
947b5f1cbeSyasuoka blks = EFI_BLKSPERSEC(ed);
95e9af5797Syasuoka if (blks == 0)
96e9af5797Syasuoka /* block size < 512. HP Stream 13 actually has such a disk. */
97e9af5797Syasuoka return (EFI_UNSUPPORTED);
987b5f1cbeSyasuoka
996202161eSyasuoka start = off / blks;
1006202161eSyasuoka end = (off + nsect + blks - 1) / blks;
1015eca72b4Skrw size = (end - start) * ed->blkio->Media->BlockSize;
1027b5f1cbeSyasuoka
1036e6a01b2Skrw status = BS->AllocatePages(AllocateAnyPages, EfiLoaderData,
1045eca72b4Skrw EFI_SIZE_TO_PAGES(size), &addr);
1056e6a01b2Skrw if (EFI_ERROR(status))
1066e6a01b2Skrw goto on_eio;
1075eca72b4Skrw data = (caddr_t)(uintptr_t)addr;
1082b0d6d04Syasuoka
1093750581dSyasuoka switch (rw) {
1103750581dSyasuoka case F_READ:
111147ac6c2Skrw status = ed->blkio->ReadBlocks(ed->blkio, ed->mediaid, start,
1125eca72b4Skrw size, data);
1137b5f1cbeSyasuoka if (EFI_ERROR(status))
1147b5f1cbeSyasuoka goto on_eio;
1155eca72b4Skrw memcpy(buf, data + DEV_BSIZE * (off - start * blks),
1166202161eSyasuoka DEV_BSIZE * nsect);
1177b5f1cbeSyasuoka break;
1187b5f1cbeSyasuoka case F_WRITE:
1195eca72b4Skrw if (ed->blkio->Media->ReadOnly)
1205eca72b4Skrw goto on_eio;
1216202161eSyasuoka if (off % blks != 0 || nsect % blks != 0) {
122147ac6c2Skrw status = ed->blkio->ReadBlocks(ed->blkio, ed->mediaid,
1235eca72b4Skrw start, size, data);
1243750581dSyasuoka if (EFI_ERROR(status))
1253750581dSyasuoka goto on_eio;
1263750581dSyasuoka }
1275eca72b4Skrw memcpy(data + DEV_BSIZE * (off - start * blks), buf,
1286202161eSyasuoka DEV_BSIZE * nsect);
129147ac6c2Skrw status = ed->blkio->WriteBlocks(ed->blkio, ed->mediaid, start,
1305eca72b4Skrw size, data);
1313750581dSyasuoka if (EFI_ERROR(status))
1323750581dSyasuoka goto on_eio;
1337b5f1cbeSyasuoka break;
1347b5f1cbeSyasuoka }
1357b5f1cbeSyasuoka
1367b5f1cbeSyasuoka on_eio:
1375eca72b4Skrw BS->FreePages(addr, EFI_SIZE_TO_PAGES(size));
1385eca72b4Skrw
1397b5f1cbeSyasuoka return (status);
1407b5f1cbeSyasuoka }
1417b5f1cbeSyasuoka
1427b5f1cbeSyasuoka static int
efid_diskio(int rw,struct diskinfo * dip,u_int off,int nsect,void * buf)1437b5f1cbeSyasuoka efid_diskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf)
1447b5f1cbeSyasuoka {
1457b5f1cbeSyasuoka EFI_STATUS status;
1467b5f1cbeSyasuoka
1477b5f1cbeSyasuoka status = efid_io(rw, dip->efi_info, off, nsect, buf);
1487b5f1cbeSyasuoka
1497b5f1cbeSyasuoka return ((EFI_ERROR(status))? -1 : 0);
1507b5f1cbeSyasuoka }
1517b5f1cbeSyasuoka
1527b5f1cbeSyasuoka /*
15393c122c5Skrw * Returns 0 if the MBR with the provided partition array is a GPT protective
15493c122c5Skrw * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only
15593c122c5Skrw * one MBR partition, an EFI partition that either covers the whole disk or as
15693c122c5Skrw * much of it as is possible with a 32bit size field.
15793c122c5Skrw *
15893c122c5Skrw * Taken from kern/subr_disk.c.
15993c122c5Skrw *
16093c122c5Skrw * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!**
16193c122c5Skrw */
162b3eeebd8Skrw static int
gpt_chk_mbr(struct dos_partition * dp,u_int64_t dsize)16312b4e828Skrw gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize)
16493c122c5Skrw {
16593c122c5Skrw struct dos_partition *dp2;
16693c122c5Skrw int efi, found, i;
16793c122c5Skrw u_int32_t psize;
16893c122c5Skrw
16993c122c5Skrw found = efi = 0;
17093c122c5Skrw for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
17193c122c5Skrw if (dp2->dp_typ == DOSPTYP_UNUSED)
17293c122c5Skrw continue;
17393c122c5Skrw found++;
17493c122c5Skrw if (dp2->dp_typ != DOSPTYP_EFI)
17593c122c5Skrw continue;
17671c0bb0bSkrw if (letoh32(dp2->dp_start) != GPTSECTOR)
17771c0bb0bSkrw continue;
17893c122c5Skrw psize = letoh32(dp2->dp_size);
17971c0bb0bSkrw if (psize <= (dsize - GPTSECTOR) || psize == UINT32_MAX)
18093c122c5Skrw efi++;
18193c122c5Skrw }
18293c122c5Skrw if (found == 1 && efi == 1)
18393c122c5Skrw return (0);
18493c122c5Skrw
18593c122c5Skrw return (1);
18693c122c5Skrw }
18793c122c5Skrw
18893c122c5Skrw /*
1890fe25aa9Skrw * Try to find the disk address of the first MBR OpenBSD partition.
1900fe25aa9Skrw *
1910fe25aa9Skrw * N.B.: must boot from a partition within first 2^32-1 sectors!
1920fe25aa9Skrw *
1930fe25aa9Skrw * Called only if the MBR on sector 0 is *not* a protective MBR
1940fe25aa9Skrw * and *does* have a valid signature.
1950fe25aa9Skrw *
1960fe25aa9Skrw * We don't check the signatures of EBR's, and they cannot be
1970fe25aa9Skrw * protective MBR's so there is no need to check for that.
1987b5f1cbeSyasuoka */
1997b5f1cbeSyasuoka static u_int
findopenbsd(efi_diskinfo_t ed,const char ** err)2007b5f1cbeSyasuoka findopenbsd(efi_diskinfo_t ed, const char **err)
2017b5f1cbeSyasuoka {
2027b5f1cbeSyasuoka EFI_STATUS status;
2037b5f1cbeSyasuoka struct dos_mbr mbr;
2047b5f1cbeSyasuoka struct dos_partition *dp;
2057b5f1cbeSyasuoka u_int mbroff = DOSBBSECTOR;
2067b5f1cbeSyasuoka u_int mbr_eoff = DOSBBSECTOR; /* Offset of MBR extended partition. */
20793c122c5Skrw int i, maxebr = DOS_MAXEBR, nextebr;
2087b5f1cbeSyasuoka
2097b5f1cbeSyasuoka again:
2107b5f1cbeSyasuoka if (!maxebr--) {
2117b5f1cbeSyasuoka *err = "too many extended partitions";
2127b5f1cbeSyasuoka return (-1);
2137b5f1cbeSyasuoka }
2147b5f1cbeSyasuoka
2157b5f1cbeSyasuoka /* Read MBR */
2167b5f1cbeSyasuoka bzero(&mbr, sizeof(mbr));
2177b5f1cbeSyasuoka status = efid_io(F_READ, ed, mbroff, 1, &mbr);
2187b5f1cbeSyasuoka if (EFI_ERROR(status)) {
2197b5f1cbeSyasuoka *err = "Disk I/O Error";
2207b5f1cbeSyasuoka return (-1);
2217b5f1cbeSyasuoka }
2227b5f1cbeSyasuoka
2237b5f1cbeSyasuoka /* Search for OpenBSD partition */
2247b5f1cbeSyasuoka nextebr = 0;
2257b5f1cbeSyasuoka for (i = 0; i < NDOSPART; i++) {
2267b5f1cbeSyasuoka dp = &mbr.dmbr_parts[i];
22793c122c5Skrw if (!dp->dp_size)
2287b5f1cbeSyasuoka continue;
2297b5f1cbeSyasuoka #ifdef BIOS_DEBUG
2307b5f1cbeSyasuoka if (debug)
2317b5f1cbeSyasuoka printf("found partition %u: "
2327b5f1cbeSyasuoka "type %u (0x%x) offset %u (0x%x)\n",
2337b5f1cbeSyasuoka (int)(dp - mbr.dmbr_parts),
2347b5f1cbeSyasuoka dp->dp_typ, dp->dp_typ,
2357b5f1cbeSyasuoka dp->dp_start, dp->dp_start);
2367b5f1cbeSyasuoka #endif
2377b5f1cbeSyasuoka if (dp->dp_typ == DOSPTYP_OPENBSD) {
2387b5f1cbeSyasuoka if (dp->dp_start > (dp->dp_start + mbroff))
2397b5f1cbeSyasuoka continue;
2407b5f1cbeSyasuoka return (dp->dp_start + mbroff);
2417b5f1cbeSyasuoka }
2427b5f1cbeSyasuoka
2437b5f1cbeSyasuoka /*
2447b5f1cbeSyasuoka * Record location of next ebr if and only if this is the first
2457b5f1cbeSyasuoka * extended partition in this boot record!
2467b5f1cbeSyasuoka */
2477b5f1cbeSyasuoka if (!nextebr && (dp->dp_typ == DOSPTYP_EXTEND ||
2487b5f1cbeSyasuoka dp->dp_typ == DOSPTYP_EXTENDL)) {
2497b5f1cbeSyasuoka nextebr = dp->dp_start + mbr_eoff;
2507b5f1cbeSyasuoka if (nextebr < dp->dp_start)
2517b5f1cbeSyasuoka nextebr = (u_int)-1;
2527b5f1cbeSyasuoka if (mbr_eoff == DOSBBSECTOR)
2537b5f1cbeSyasuoka mbr_eoff = dp->dp_start;
2547b5f1cbeSyasuoka }
2557b5f1cbeSyasuoka }
2567b5f1cbeSyasuoka
2577b5f1cbeSyasuoka if (nextebr && nextebr != (u_int)-1) {
2587b5f1cbeSyasuoka mbroff = nextebr;
2597b5f1cbeSyasuoka goto again;
2607b5f1cbeSyasuoka }
2617b5f1cbeSyasuoka
2627b5f1cbeSyasuoka return (-1);
2637b5f1cbeSyasuoka }
2647b5f1cbeSyasuoka
2650fe25aa9Skrw /*
2660fe25aa9Skrw * Try to find the disk address of the first GPT OpenBSD partition.
2670fe25aa9Skrw *
2680fe25aa9Skrw * N.B.: must boot from a partition within first 2^32-1 sectors!
2690fe25aa9Skrw *
2700fe25aa9Skrw * Called only if the MBR on sector 0 *is* a protective MBR
2710fe25aa9Skrw * with a valid signature and sector 1 is a valid GPT header.
2720fe25aa9Skrw */
2730fe25aa9Skrw static u_int
findopenbsd_gpt(efi_diskinfo_t ed,const char ** err)2747b5f1cbeSyasuoka findopenbsd_gpt(efi_diskinfo_t ed, const char **err)
2757b5f1cbeSyasuoka {
2767b5f1cbeSyasuoka EFI_STATUS status;
2777b5f1cbeSyasuoka struct gpt_header gh;
2785ca0d521Skrw int i, part, found;
2797b5f1cbeSyasuoka uint64_t lba;
28078160737Syasuoka uint32_t orig_csum, new_csum;
281a8a56a2cSkrw uint32_t ghsize, ghpartsize, ghpartnum, ghpartspersec;
2825ca0d521Skrw uint32_t gpsectors;
2837b5f1cbeSyasuoka const char openbsd_uuid_code[] = GPT_UUID_OPENBSD;
2845ca0d521Skrw struct gpt_partition gp;
2857b5f1cbeSyasuoka static struct uuid *openbsd_uuid = NULL, openbsd_uuid_space;
28678160737Syasuoka static u_char buf[4096];
2877b5f1cbeSyasuoka
2887b5f1cbeSyasuoka /* Prepare OpenBSD UUID */
2897b5f1cbeSyasuoka if (openbsd_uuid == NULL) {
2907b5f1cbeSyasuoka /* XXX: should be replaced by uuid_dec_be() */
2917b5f1cbeSyasuoka memcpy(&openbsd_uuid_space, openbsd_uuid_code,
2927b5f1cbeSyasuoka sizeof(openbsd_uuid_space));
2937b5f1cbeSyasuoka openbsd_uuid_space.time_low =
2947b5f1cbeSyasuoka betoh32(openbsd_uuid_space.time_low);
2957b5f1cbeSyasuoka openbsd_uuid_space.time_mid =
2967b5f1cbeSyasuoka betoh16(openbsd_uuid_space.time_mid);
2977b5f1cbeSyasuoka openbsd_uuid_space.time_hi_and_version =
2987b5f1cbeSyasuoka betoh16(openbsd_uuid_space.time_hi_and_version);
2997b5f1cbeSyasuoka
3007b5f1cbeSyasuoka openbsd_uuid = &openbsd_uuid_space;
3017b5f1cbeSyasuoka }
3027b5f1cbeSyasuoka
30378160737Syasuoka if (EFI_BLKSPERSEC(ed) > 8) {
30478160737Syasuoka *err = "disk sector > 4096 bytes\n";
30578160737Syasuoka return (-1);
30678160737Syasuoka }
30778160737Syasuoka
30871c0bb0bSkrw /* GPT Header */
30971c0bb0bSkrw lba = GPTSECTOR;
31078160737Syasuoka status = efid_io(F_READ, ed, EFI_SECTOBLK(ed, lba), EFI_BLKSPERSEC(ed),
31178160737Syasuoka buf);
31278160737Syasuoka if (EFI_ERROR(status)) {
31378160737Syasuoka *err = "Disk I/O Error";
31478160737Syasuoka return (-1);
31578160737Syasuoka }
3167b5f1cbeSyasuoka memcpy(&gh, buf, sizeof(gh));
3177b5f1cbeSyasuoka
3187b5f1cbeSyasuoka /* Check signature */
3197b5f1cbeSyasuoka if (letoh64(gh.gh_sig) != GPTSIGNATURE) {
3207b5f1cbeSyasuoka *err = "bad GPT signature\n";
3217b5f1cbeSyasuoka return (-1);
3227b5f1cbeSyasuoka }
3237b5f1cbeSyasuoka
324a8a56a2cSkrw if (letoh32(gh.gh_rev) != GPTREVISION) {
325a8a56a2cSkrw *err = "bad GPT revision\n";
326a8a56a2cSkrw return (-1);
327a8a56a2cSkrw }
328a8a56a2cSkrw
329a8a56a2cSkrw ghsize = letoh32(gh.gh_size);
330a8a56a2cSkrw if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header)) {
331a8a56a2cSkrw *err = "bad GPT header size\n";
332a8a56a2cSkrw return (-1);
333a8a56a2cSkrw }
334a8a56a2cSkrw
33578160737Syasuoka /* Check checksum */
33678160737Syasuoka orig_csum = gh.gh_csum;
33778160737Syasuoka gh.gh_csum = 0;
338a8a56a2cSkrw new_csum = crc32(0, (unsigned char *)&gh, ghsize);
33978160737Syasuoka gh.gh_csum = orig_csum;
34078160737Syasuoka if (letoh32(orig_csum) != new_csum) {
34178160737Syasuoka *err = "bad GPT header checksum\n";
342a3344f80Skrw return (-1);
34378160737Syasuoka }
34478160737Syasuoka
34578160737Syasuoka lba = letoh64(gh.gh_part_lba);
34678160737Syasuoka ghpartsize = letoh32(gh.gh_part_size);
34778160737Syasuoka ghpartspersec = ed->blkio->Media->BlockSize / ghpartsize;
34878160737Syasuoka ghpartnum = letoh32(gh.gh_part_num);
3495ca0d521Skrw gpsectors = (ghpartnum + ghpartspersec - 1) / ghpartspersec;
3505ca0d521Skrw new_csum = crc32(0L, Z_NULL, 0);
3515ca0d521Skrw found = 0;
3525ca0d521Skrw for (i = 0; i < gpsectors; i++, lba++) {
35378160737Syasuoka status = efid_io(F_READ, ed, EFI_SECTOBLK(ed, lba),
35478160737Syasuoka EFI_BLKSPERSEC(ed), buf);
35578160737Syasuoka if (EFI_ERROR(status)) {
35678160737Syasuoka *err = "Disk I/O Error";
3577b5f1cbeSyasuoka return (-1);
3587b5f1cbeSyasuoka }
3595ca0d521Skrw for (part = 0; part < ghpartspersec; part++) {
3605ca0d521Skrw if (ghpartnum == 0)
3615ca0d521Skrw break;
3625ca0d521Skrw new_csum = crc32(new_csum, buf + part * sizeof(gp),
3635ca0d521Skrw sizeof(gp));
3645ca0d521Skrw ghpartnum--;
3655ca0d521Skrw if (found)
3665ca0d521Skrw continue;
3675ca0d521Skrw memcpy(&gp, buf + part * sizeof(gp), sizeof(gp));
3685ca0d521Skrw if (memcmp(&gp.gp_type, openbsd_uuid,
3697b5f1cbeSyasuoka sizeof(struct uuid)) == 0)
3705ca0d521Skrw found = 1;
3717b5f1cbeSyasuoka }
3725ca0d521Skrw }
37368d6f2cfSkrw if (new_csum != letoh32(gh.gh_part_csum)) {
37468d6f2cfSkrw *err = "bad GPT entries checksum\n";
37568d6f2cfSkrw return (-1);
37668d6f2cfSkrw }
3770fe25aa9Skrw if (found) {
3780fe25aa9Skrw lba = letoh64(gp.gp_lba_start);
3790fe25aa9Skrw /* Bootloaders do not current handle addresses > UINT_MAX! */
3800fe25aa9Skrw if (lba > UINT_MAX || EFI_SECTOBLK(ed, lba) > UINT_MAX) {
3810fe25aa9Skrw *err = "OpenBSD Partition LBA > 2**32 - 1";
3820fe25aa9Skrw return (-1);
3830fe25aa9Skrw }
3840fe25aa9Skrw return (u_int)lba;
3850fe25aa9Skrw }
3867b5f1cbeSyasuoka
3877b5f1cbeSyasuoka return (-1);
3887b5f1cbeSyasuoka }
3897b5f1cbeSyasuoka
3907b5f1cbeSyasuoka const char *
efi_getdisklabel(efi_diskinfo_t ed,struct disklabel * label)3917b5f1cbeSyasuoka efi_getdisklabel(efi_diskinfo_t ed, struct disklabel *label)
3927b5f1cbeSyasuoka {
3937b5f1cbeSyasuoka u_int start = 0;
3940fe25aa9Skrw uint8_t buf[DEV_BSIZE];
3950fe25aa9Skrw struct dos_partition dosparts[NDOSPART];
3960fe25aa9Skrw EFI_STATUS status;
3977b5f1cbeSyasuoka const char *err = NULL;
3987b5f1cbeSyasuoka int error;
3997b5f1cbeSyasuoka
4000fe25aa9Skrw /*
4010fe25aa9Skrw * Read sector 0. Ensure it has a valid MBR signature.
4020fe25aa9Skrw *
4030fe25aa9Skrw * If it's a protective MBR then try to find the disklabel via
4040fe25aa9Skrw * GPT. If it's not a protective MBR, try to find the disklabel
4050fe25aa9Skrw * via MBR.
4060fe25aa9Skrw */
4070fe25aa9Skrw memset(buf, 0, sizeof(buf));
4080fe25aa9Skrw status = efid_io(F_READ, ed, DOSBBSECTOR, 1, buf);
4090fe25aa9Skrw if (EFI_ERROR(status))
4100fe25aa9Skrw return ("Disk I/O Error");
4117b5f1cbeSyasuoka
4120fe25aa9Skrw /* Check MBR signature. */
413055ff051Syasuoka if (buf[510] != 0x55 || buf[511] != 0xaa) {
414055ff051Syasuoka if (efi_getdisklabel_cd9660(ed, label) == 0)
415055ff051Syasuoka return (NULL);
4160fe25aa9Skrw return ("invalid MBR signature");
417055ff051Syasuoka }
4180fe25aa9Skrw
4190fe25aa9Skrw memcpy(dosparts, buf+DOSPARTOFF, sizeof(dosparts));
4200fe25aa9Skrw
4210fe25aa9Skrw /* check for GPT protective MBR. */
4220fe25aa9Skrw if (gpt_chk_mbr(dosparts, ed->blkio->Media->LastBlock + 1) == 0) {
4230fe25aa9Skrw start = findopenbsd_gpt(ed, &err);
4240fe25aa9Skrw if (start == (u_int)-1) {
4250fe25aa9Skrw if (err != NULL)
4260fe25aa9Skrw return (err);
4270fe25aa9Skrw return ("no OpenBSD GPT partition");
4280fe25aa9Skrw }
4290fe25aa9Skrw } else {
4307b5f1cbeSyasuoka start = findopenbsd(ed, &err);
4317b5f1cbeSyasuoka if (start == (u_int)-1) {
4327b5f1cbeSyasuoka if (err != NULL)
4337b5f1cbeSyasuoka return (err);
4340fe25aa9Skrw return "no OpenBSD MBR partition\n";
4350fe25aa9Skrw }
4367b5f1cbeSyasuoka }
4377b5f1cbeSyasuoka
4387b5f1cbeSyasuoka /* Load BSD disklabel */
4397b5f1cbeSyasuoka #ifdef BIOS_DEBUG
4407b5f1cbeSyasuoka if (debug)
4419e746c39Skrw printf("loading disklabel @ %u\n", start + DOS_LABELSECTOR);
4427b5f1cbeSyasuoka #endif
4437b5f1cbeSyasuoka /* read disklabel */
444dd9fde97Syasuoka error = efid_io(F_READ, ed, EFI_SECTOBLK(ed, start) + DOS_LABELSECTOR,
445dd9fde97Syasuoka 1, buf);
4467b5f1cbeSyasuoka
4477b5f1cbeSyasuoka if (error)
4487b5f1cbeSyasuoka return "failed to read disklabel";
4497b5f1cbeSyasuoka
4507b5f1cbeSyasuoka /* Fill in disklabel */
4517b5f1cbeSyasuoka return (getdisklabel(buf, label));
4527b5f1cbeSyasuoka }
4537b5f1cbeSyasuoka
454055ff051Syasuoka static int
efi_getdisklabel_cd9660(efi_diskinfo_t ed,struct disklabel * label)455055ff051Syasuoka efi_getdisklabel_cd9660(efi_diskinfo_t ed, struct disklabel *label)
456055ff051Syasuoka {
457055ff051Syasuoka uint8_t buf[DEV_BSIZE];
458055ff051Syasuoka EFI_STATUS status;
459055ff051Syasuoka
460*f4f4f64eSjsg status = efid_io(F_READ, ed, 64, 1, buf);
461055ff051Syasuoka if (EFI_ERROR(status))
462*f4f4f64eSjsg return -1;
463*f4f4f64eSjsg if (buf[0] != ISO_VD_PRIMARY || bcmp(buf + 1, ISO_STANDARD_ID, 5) != 0)
464*f4f4f64eSjsg return -1;
465055ff051Syasuoka
466055ff051Syasuoka /* Create an imaginary disk label */
467055ff051Syasuoka label->d_secsize = 2048;
468055ff051Syasuoka label->d_ntracks = 1;
469055ff051Syasuoka label->d_nsectors = 100;
470055ff051Syasuoka label->d_ncylinders = 1;
471055ff051Syasuoka label->d_secpercyl = label->d_ntracks * label->d_nsectors;
472055ff051Syasuoka
473055ff051Syasuoka strncpy(label->d_typename, "ATAPI CD-ROM", sizeof(label->d_typename));
474055ff051Syasuoka label->d_type = DTYPE_ATAPI;
475055ff051Syasuoka
476055ff051Syasuoka strncpy(label->d_packname, "fictitious", sizeof(label->d_packname));
477055ff051Syasuoka DL_SETDSIZE(label, 100);
478055ff051Syasuoka
479055ff051Syasuoka /* 'a' partition covering the "whole" disk */
480055ff051Syasuoka DL_SETPOFFSET(&label->d_partitions[0], 0);
481055ff051Syasuoka DL_SETPSIZE(&label->d_partitions[0], 100);
482055ff051Syasuoka label->d_partitions[0].p_fstype = FS_UNUSED;
483055ff051Syasuoka
484055ff051Syasuoka /* The raw partition is special */
485055ff051Syasuoka DL_SETPOFFSET(&label->d_partitions[RAW_PART], 0);
486055ff051Syasuoka DL_SETPSIZE(&label->d_partitions[RAW_PART], 100);
487055ff051Syasuoka label->d_partitions[RAW_PART].p_fstype = FS_UNUSED;
488055ff051Syasuoka
489055ff051Syasuoka label->d_npartitions = MAXPARTITIONS;
490055ff051Syasuoka
491055ff051Syasuoka label->d_magic = DISKMAGIC;
492055ff051Syasuoka label->d_magic2 = DISKMAGIC;
493055ff051Syasuoka label->d_checksum = dkcksum(label);
494055ff051Syasuoka
495055ff051Syasuoka return (0);
496055ff051Syasuoka }
497055ff051Syasuoka
4987b5f1cbeSyasuoka int
efiopen(struct open_file * f,...)4997b5f1cbeSyasuoka efiopen(struct open_file *f, ...)
5007b5f1cbeSyasuoka {
5017b5f1cbeSyasuoka #ifdef SOFTRAID
5027b5f1cbeSyasuoka struct sr_boot_volume *bv;
5037b5f1cbeSyasuoka #endif
5047b5f1cbeSyasuoka register char *cp, **file;
5057b5f1cbeSyasuoka dev_t maj, unit, part;
5067b5f1cbeSyasuoka struct diskinfo *dip;
5077b5f1cbeSyasuoka int biosdev, devlen;
5087b5f1cbeSyasuoka #if 0
5097b5f1cbeSyasuoka const char *st;
5107b5f1cbeSyasuoka #endif
5117b5f1cbeSyasuoka va_list ap;
5127b5f1cbeSyasuoka char *dev;
5137b5f1cbeSyasuoka
5147b5f1cbeSyasuoka va_start(ap, f);
5157b5f1cbeSyasuoka cp = *(file = va_arg(ap, char **));
5167b5f1cbeSyasuoka va_end(ap);
5177b5f1cbeSyasuoka
5187b5f1cbeSyasuoka #ifdef EFI_DEBUG
5197b5f1cbeSyasuoka if (debug)
5207b5f1cbeSyasuoka printf("%s\n", cp);
5217b5f1cbeSyasuoka #endif
5227b5f1cbeSyasuoka
5237b5f1cbeSyasuoka f->f_devdata = NULL;
5247b5f1cbeSyasuoka
5257b5f1cbeSyasuoka /* Search for device specification. */
5267b5f1cbeSyasuoka dev = cp;
5277b5f1cbeSyasuoka if (cp[4] == ':')
5287b5f1cbeSyasuoka devlen = 2;
5297b5f1cbeSyasuoka else if (cp[5] == ':')
5307b5f1cbeSyasuoka devlen = 3;
5317b5f1cbeSyasuoka else
5327b5f1cbeSyasuoka return ENOENT;
5337b5f1cbeSyasuoka cp += devlen;
5347b5f1cbeSyasuoka
5357b5f1cbeSyasuoka /* Get unit. */
5367b5f1cbeSyasuoka if ('0' <= *cp && *cp <= '9')
5377b5f1cbeSyasuoka unit = *cp++ - '0';
5387b5f1cbeSyasuoka else {
5397b5f1cbeSyasuoka printf("Bad unit number\n");
5407b5f1cbeSyasuoka return EUNIT;
5417b5f1cbeSyasuoka }
5427b5f1cbeSyasuoka
5437b5f1cbeSyasuoka /* Get partition. */
5447b5f1cbeSyasuoka if ('a' <= *cp && *cp <= 'p')
5457b5f1cbeSyasuoka part = *cp++ - 'a';
5467b5f1cbeSyasuoka else {
5477b5f1cbeSyasuoka printf("Bad partition\n");
5487b5f1cbeSyasuoka return EPART;
5497b5f1cbeSyasuoka }
5507b5f1cbeSyasuoka
5517b5f1cbeSyasuoka /* Get filename. */
5527b5f1cbeSyasuoka cp++; /* skip ':' */
5537b5f1cbeSyasuoka if (*cp != 0)
5547b5f1cbeSyasuoka *file = cp;
5557b5f1cbeSyasuoka else
5567b5f1cbeSyasuoka f->f_flags |= F_RAW;
5577b5f1cbeSyasuoka
5587b5f1cbeSyasuoka #ifdef SOFTRAID
5597b5f1cbeSyasuoka /* Intercept softraid disks. */
5607b5f1cbeSyasuoka if (strncmp("sr", dev, 2) == 0) {
5614b81c294Skn /* We only support read-only softraid. */
5624b81c294Skn f->f_flags |= F_NOWRITE;
5637b5f1cbeSyasuoka
5647b5f1cbeSyasuoka /* Create a fake diskinfo for this softraid volume. */
5657b5f1cbeSyasuoka SLIST_FOREACH(bv, &sr_volumes, sbv_link)
5667b5f1cbeSyasuoka if (bv->sbv_unit == unit)
5677b5f1cbeSyasuoka break;
5687b5f1cbeSyasuoka if (bv == NULL) {
5697b5f1cbeSyasuoka printf("Unknown device: sr%d\n", unit);
5707b5f1cbeSyasuoka return EADAPT;
5717b5f1cbeSyasuoka }
5727b5f1cbeSyasuoka
573855f8c03Sstsp if ((bv->sbv_level == 'C' || bv->sbv_level == 0x1C) &&
574855f8c03Sstsp bv->sbv_keys == NULL) {
57527bea9a3Sjsing if (sr_crypto_unlock_volume(bv) != 0)
5767b5f1cbeSyasuoka return EPERM;
577855f8c03Sstsp }
5787b5f1cbeSyasuoka
5797b5f1cbeSyasuoka if (bv->sbv_diskinfo == NULL) {
5807b5f1cbeSyasuoka dip = alloc(sizeof(struct diskinfo));
5817b5f1cbeSyasuoka bzero(dip, sizeof(*dip));
5827b5f1cbeSyasuoka dip->diskio = efid_diskio;
5837b5f1cbeSyasuoka dip->strategy = efistrategy;
5847b5f1cbeSyasuoka bv->sbv_diskinfo = dip;
5857b5f1cbeSyasuoka dip->sr_vol = bv;
5867b5f1cbeSyasuoka dip->bios_info.flags |= BDI_BADLABEL;
5877b5f1cbeSyasuoka }
5887b5f1cbeSyasuoka
5897b5f1cbeSyasuoka dip = bv->sbv_diskinfo;
5907b5f1cbeSyasuoka
5917b5f1cbeSyasuoka if (dip->bios_info.flags & BDI_BADLABEL) {
5927b5f1cbeSyasuoka /* Attempt to read disklabel. */
5937b5f1cbeSyasuoka bv->sbv_part = 'c';
5947b5f1cbeSyasuoka if (sr_getdisklabel(bv, &dip->disklabel))
5957b5f1cbeSyasuoka return ERDLAB;
5967b5f1cbeSyasuoka dip->bios_info.flags &= ~BDI_BADLABEL;
5976ce082ffSyasuoka check_hibernate(dip);
5987b5f1cbeSyasuoka }
5997b5f1cbeSyasuoka
6007b5f1cbeSyasuoka bv->sbv_part = part + 'a';
6017b5f1cbeSyasuoka
6027b5f1cbeSyasuoka bootdev_dip = dip;
6037b5f1cbeSyasuoka f->f_devdata = dip;
6047b5f1cbeSyasuoka
6057b5f1cbeSyasuoka return 0;
6067b5f1cbeSyasuoka }
6077b5f1cbeSyasuoka #endif
6087b5f1cbeSyasuoka for (maj = 0; maj < nbdevs &&
6097b5f1cbeSyasuoka strncmp(dev, bdevs[maj], devlen); maj++);
6107b5f1cbeSyasuoka if (maj >= nbdevs) {
6117b5f1cbeSyasuoka printf("Unknown device: ");
6127b5f1cbeSyasuoka for (cp = *file; *cp != ':'; cp++)
6137b5f1cbeSyasuoka putchar(*cp);
6147b5f1cbeSyasuoka putchar('\n');
6157b5f1cbeSyasuoka return EADAPT;
6167b5f1cbeSyasuoka }
6177b5f1cbeSyasuoka
6187b5f1cbeSyasuoka biosdev = unit;
6197b5f1cbeSyasuoka switch (maj) {
6207b5f1cbeSyasuoka case 0: /* wd */
6217b5f1cbeSyasuoka case 4: /* sd */
6227b5f1cbeSyasuoka case 17: /* hd */
6237b5f1cbeSyasuoka biosdev |= 0x80;
6247b5f1cbeSyasuoka break;
6257b5f1cbeSyasuoka case 2: /* fd */
6267b5f1cbeSyasuoka break;
6277b5f1cbeSyasuoka case 6: /* cd */
62847026318Syasuoka biosdev |= 0xe0;
6297b5f1cbeSyasuoka break;
6307b5f1cbeSyasuoka default:
6317b5f1cbeSyasuoka return ENXIO;
6327b5f1cbeSyasuoka }
6337b5f1cbeSyasuoka
6347b5f1cbeSyasuoka /* Find device */
6357b5f1cbeSyasuoka dip = dklookup(biosdev);
6367b5f1cbeSyasuoka if (dip == NULL)
6377b5f1cbeSyasuoka return ENXIO;
6387b5f1cbeSyasuoka bootdev_dip = dip;
6397b5f1cbeSyasuoka
6407b5f1cbeSyasuoka /* Fix up bootdev */
6417b5f1cbeSyasuoka { dev_t bsd_dev;
6427b5f1cbeSyasuoka bsd_dev = dip->bios_info.bsd_dev;
6437b5f1cbeSyasuoka dip->bsddev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
6447b5f1cbeSyasuoka B_CONTROLLER(bsd_dev), unit, part);
6457b5f1cbeSyasuoka dip->bootdev = MAKEBOOTDEV(B_TYPE(bsd_dev), B_ADAPTOR(bsd_dev),
6467b5f1cbeSyasuoka B_CONTROLLER(bsd_dev), B_UNIT(bsd_dev), part);
6477b5f1cbeSyasuoka }
6487b5f1cbeSyasuoka
6497b5f1cbeSyasuoka #if 0
6507b5f1cbeSyasuoka dip->bios_info.bsd_dev = dip->bootdev;
6517b5f1cbeSyasuoka bootdev = dip->bootdev;
6527b5f1cbeSyasuoka #endif
6537b5f1cbeSyasuoka
6547b5f1cbeSyasuoka #ifdef EFI_DEBUG
6557b5f1cbeSyasuoka if (debug) {
6567b5f1cbeSyasuoka printf("BIOS geometry: heads=%u, s/t=%u; EDD=%d\n",
6577b5f1cbeSyasuoka dip->bios_info.bios_heads, dip->bios_info.bios_sectors,
6587b5f1cbeSyasuoka dip->bios_info.bios_edd);
6597b5f1cbeSyasuoka }
6607b5f1cbeSyasuoka #endif
6617b5f1cbeSyasuoka
6627b5f1cbeSyasuoka #if 0
6637b5f1cbeSyasuoka /*
6647b5f1cbeSyasuoka * XXX In UEFI, media change can be detected by MediaID
6657b5f1cbeSyasuoka */
6667b5f1cbeSyasuoka /* Try for disklabel again (might be removable media) */
6677b5f1cbeSyasuoka if (dip->bios_info.flags & BDI_BADLABEL) {
6687b5f1cbeSyasuoka st = efi_getdisklabel(dip->efi_info, &dip->disklabel);
6697b5f1cbeSyasuoka #ifdef EFI_DEBUG
6707b5f1cbeSyasuoka if (debug && st)
6717b5f1cbeSyasuoka printf("%s\n", st);
6727b5f1cbeSyasuoka #endif
6737b5f1cbeSyasuoka if (!st) {
6747b5f1cbeSyasuoka dip->bios_info.flags &= ~BDI_BADLABEL;
6757b5f1cbeSyasuoka dip->bios_info.flags |= BDI_GOODLABEL;
6767b5f1cbeSyasuoka } else
6777b5f1cbeSyasuoka return ERDLAB;
6787b5f1cbeSyasuoka }
6797b5f1cbeSyasuoka #endif
6807b5f1cbeSyasuoka f->f_devdata = dip;
6817b5f1cbeSyasuoka
6827b5f1cbeSyasuoka return 0;
6837b5f1cbeSyasuoka }
6847b5f1cbeSyasuoka
6857b5f1cbeSyasuoka int
efistrategy(void * devdata,int rw,daddr_t blk,size_t size,void * buf,size_t * rsize)6863e58d19eSkrw efistrategy(void *devdata, int rw, daddr_t blk, size_t size, void *buf,
6877b5f1cbeSyasuoka size_t *rsize)
6887b5f1cbeSyasuoka {
6897b5f1cbeSyasuoka struct diskinfo *dip = (struct diskinfo *)devdata;
6907b5f1cbeSyasuoka u_int8_t error = 0;
6917b5f1cbeSyasuoka size_t nsect;
6927b5f1cbeSyasuoka
6937b5f1cbeSyasuoka #ifdef SOFTRAID
6947b5f1cbeSyasuoka /* Intercept strategy for softraid volumes. */
6957b5f1cbeSyasuoka if (dip->sr_vol)
6967b5f1cbeSyasuoka return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize);
6977b5f1cbeSyasuoka #endif
6987b5f1cbeSyasuoka nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE;
699a14e0543Syasuoka blk += DL_SECTOBLK(&dip->disklabel,
700a14e0543Syasuoka dip->disklabel.d_partitions[B_PARTITION(dip->bsddev)].p_offset);
7017b5f1cbeSyasuoka
7027b5f1cbeSyasuoka if (blk < 0)
7037b5f1cbeSyasuoka error = EINVAL;
7047b5f1cbeSyasuoka else
7057b5f1cbeSyasuoka error = dip->diskio(rw, dip, blk, nsect, buf);
7067b5f1cbeSyasuoka
7077b5f1cbeSyasuoka #ifdef EFI_DEBUG
7087b5f1cbeSyasuoka if (debug) {
7097b5f1cbeSyasuoka if (error != 0)
7107b5f1cbeSyasuoka printf("=0x%x(%s)", error, error);
7117b5f1cbeSyasuoka putchar('\n');
7127b5f1cbeSyasuoka }
7137b5f1cbeSyasuoka #endif
7147b5f1cbeSyasuoka if (rsize != NULL)
7157b5f1cbeSyasuoka *rsize = nsect * DEV_BSIZE;
7167b5f1cbeSyasuoka
7177b5f1cbeSyasuoka return (error);
7187b5f1cbeSyasuoka }
7197b5f1cbeSyasuoka
7207b5f1cbeSyasuoka int
eficlose(struct open_file * f)7217b5f1cbeSyasuoka eficlose(struct open_file *f)
7227b5f1cbeSyasuoka {
7237b5f1cbeSyasuoka f->f_devdata = NULL;
7247b5f1cbeSyasuoka
7257b5f1cbeSyasuoka return 0;
7267b5f1cbeSyasuoka }
7277b5f1cbeSyasuoka
7287b5f1cbeSyasuoka int
efiioctl(struct open_file * f,u_long cmd,void * data)7297b5f1cbeSyasuoka efiioctl(struct open_file *f, u_long cmd, void *data)
7307b5f1cbeSyasuoka {
7317b5f1cbeSyasuoka
7327b5f1cbeSyasuoka return 0;
7337b5f1cbeSyasuoka }
73479a80d09Syasuoka
73579a80d09Syasuoka void
efi_dump_diskinfo(void)73679a80d09Syasuoka efi_dump_diskinfo(void)
73779a80d09Syasuoka {
73879a80d09Syasuoka efi_diskinfo_t ed;
73979a80d09Syasuoka struct diskinfo *dip;
74079a80d09Syasuoka bios_diskinfo_t *bdi;
74179a80d09Syasuoka uint64_t siz;
74279a80d09Syasuoka const char *sizu;
74379a80d09Syasuoka
74479a80d09Syasuoka printf("Disk\tBlkSiz\tIoAlign\tSize\tFlags\tChecksum\n");
74579a80d09Syasuoka TAILQ_FOREACH(dip, &disklist, list) {
74679a80d09Syasuoka bdi = &dip->bios_info;
74779a80d09Syasuoka ed = dip->efi_info;
74879a80d09Syasuoka
749af596e08Skrw siz = (ed->blkio->Media->LastBlock + 1) *
750af596e08Skrw ed->blkio->Media->BlockSize;
75179a80d09Syasuoka siz /= 1024 * 1024;
75279a80d09Syasuoka if (siz < 10000)
75379a80d09Syasuoka sizu = "MB";
75479a80d09Syasuoka else {
75579a80d09Syasuoka siz /= 1024;
75679a80d09Syasuoka sizu = "GB";
75779a80d09Syasuoka }
75879a80d09Syasuoka
75947026318Syasuoka printf("%cd%d\t%u\t%u\t%u%s\t0x%x\t0x%x\t%s\n",
76047026318Syasuoka (B_TYPE(bdi->bsd_dev) == 6)? 'c' : 'h',
76147026318Syasuoka (bdi->bios_number & 0x1f),
76279a80d09Syasuoka ed->blkio->Media->BlockSize,
7634bd5cee5Syasuoka ed->blkio->Media->IoAlign, (unsigned)siz, sizu,
76479a80d09Syasuoka bdi->flags, bdi->checksum,
76579a80d09Syasuoka (ed->blkio->Media->RemovableMedia)? "Removable" : "");
76679a80d09Syasuoka }
76779a80d09Syasuoka }
768