> Date: Wed, 30 Jan 2019 22:31:31 +0100
> From: Patrick Wildt <[email protected]>
> 
> Hi,
> 
> to boot a pinebook with softraid crypto there are three parts that need
> to be implemented, which this diff hopefully does well enough.
> 
> First, our EFI bootloader so far only supports one disk, so we need to
> extend this so we can see all connected block devices.  The second part
> is adding the softraid code, which probes for softraid partitions on the
> block devices and "spawns" its own block device.  At last, we need to
> push the softraid uuid and key up to the kernel.
> 
> Pushing the informaton to the kernel is the easiest part.  We can add
> another openbsd-specific property in the device tree which we read out
> early on, so that we can zero the space in the device tree so it can not
> be read by anyone else.
> 
> For the other part there's a bit more to do.  Very early on efiboot
> looks for the boot device.  While doing that, we create a list of block
> devices.  While there, already try to read the disklabel because after
> this the softraid probing needs to know the partition table.
> 
> We then call srprobe() which will go over the disklist to look for a
> disk that contains RAID volumes, but calling the disk's diskio and
> strategy function to read from the device.  This creates the sr_volumes
> list of softraid volumes.  The MI boot code will then look for the boot
> device name by calling devboot().  If we don't have the device path for
> the boot device, it's a PXE boot.  Otherwise we will find it in either
> the disklist or sr_volumes list.
> 
> The next part is the MI code opening the device, looking for a file-
> system.  The boot device name now is e.g. sr0a, which will then be
> looked up in the devsw[] array.  From there it's straight forward.
> Softraid maps the unit number to a volume, the volume already has a
> pointer to the diskinfo structure from the actual device and then
> calls the IO functions of that device.
> 
> softraid_arm64.[ch] is copied from amd64 and adjusted a little bit
> for arm64, including adding the small devsw[] abstraction.
> 
> With this I can successfully boot from softraid crypto on bluhm@'s
> Pinebook.
> 
> Feedback?

Still need to review this properly.  But why is one of the properties
called openbsd,bootsr-maskkey?  openbsd,bootsr-key would make more
sense.  Or maybe openbsd,sr-bootuuid and openbsd,sr-bootkey?

I think I'd prefer the latter.

Mark

> diff --git sys/arch/arm64/arm64/machdep.c sys/arch/arm64/arm64/machdep.c
> index 45f6451066a..03bc8464f3a 100644
> --- sys/arch/arm64/arm64/machdep.c
> +++ sys/arch/arm64/arm64/machdep.c
> @@ -30,6 +30,7 @@
>  #include <sys/msgbuf.h>
>  #include <sys/buf.h>
>  #include <sys/termios.h>
> +#include <sys/sensors.h>
>  
>  #include <net/if.h>
>  #include <uvm/uvm.h>
> @@ -49,6 +50,11 @@
>  
>  #include <dev/acpi/efi.h>
>  
> +#include "softraid.h"
> +#if NSOFTRAID > 0
> +#include <dev/softraidvar.h>
> +#endif
> +
>  char *boot_args = NULL;
>  char *boot_file = "";
>  
> @@ -826,6 +832,22 @@ initarm(struct arm64_bootparams *abp)
>                       bootmac = lladdr;
>               }
>  
> +             len = fdt_node_property(node, "openbsd,bootsr-uuid", &prop);
> +#if NSOFTRAID > 0
> +             if (len == sizeof(sr_bootuuid))
> +                     memcpy(&sr_bootuuid, prop, sizeof(sr_bootuuid));
> +#endif
> +             if (len > 0)
> +                     explicit_bzero(prop, len);
> +
> +             len = fdt_node_property(node, "openbsd,bootsr-maskkey", &prop);
> +#if NSOFTRAID > 0
> +             if (len == sizeof(sr_bootkey))
> +                     memcpy(&sr_bootkey, prop, sizeof(sr_bootkey));
> +#endif
> +             if (len > 0)
> +                     explicit_bzero(prop, len);
> +
>               len = fdt_node_property(node, "openbsd,uefi-mmap-start", &prop);
>               if (len == sizeof(mmap_start))
>                       mmap_start = bemtoh64((uint64_t *)prop);
> diff --git sys/arch/arm64/stand/efiboot/Makefile 
> sys/arch/arm64/stand/efiboot/Makefile
> index 36eecd6ca9c..d0ec46662ee 100644
> --- sys/arch/arm64/stand/efiboot/Makefile
> +++ sys/arch/arm64/stand/efiboot/Makefile
> @@ -10,6 +10,7 @@ INSTALL_STRIP=
>  BINDIR=              /usr/mdec
>  SRCS=                start.S self_reloc.c efiboot.c conf.c exec.c efiacpi.c
>  SRCS+=               efidev.c efipxe.c efirng.c fdt.c dt_blob.S
> +SRCS+=               softraid_arm64.c
>  
>  S=           ${.CURDIR}/../../../..
>  EFIDIR=              ${S}/stand/efi
> @@ -31,6 +32,8 @@ SRCS+=      close.c closeall.c cons.c cread.c dev.c 
> disklabel.c dkcksum.c fstat.c \
>  SRCS+=       loadfile.c
>  SRCS+=       ufs.c
>  SRCS+=       arp.c ether.c globals.c in_cksum.c net.c netif.c netudp.c tftp.c
> +SRCS+=       aes_xts.c bcrypt_pbkdf.c blowfish.c explicit_bzero.c 
> hmac_sha1.c \
> +     pkcs5_pbkdf2.c rijndael.c sha1.c sha2.c softraid.c
>  
>  .PATH:       ${S}/lib/libkern/arch/arm64 ${S}/lib/libkern
>  SRCS+=       divdi3.c moddi3.c qdivrem.c strlcpy.c strlen.c
> diff --git sys/arch/arm64/stand/efiboot/conf.c 
> sys/arch/arm64/stand/efiboot/conf.c
> index 5e8fd5fa0e7..be301b4a9d4 100644
> --- sys/arch/arm64/stand/efiboot/conf.c
> +++ sys/arch/arm64/stand/efiboot/conf.c
> @@ -27,14 +27,23 @@
>   */
>  
>  #include <sys/param.h>
> +#include <sys/queue.h>
> +#include <sys/disklabel.h>
>  #include <lib/libsa/stand.h>
>  #include <lib/libsa/tftp.h>
>  #include <lib/libsa/ufs.h>
>  #include <dev/cons.h>
>  
> +#include <dev/biovar.h>
> +#include <dev/softraidvar.h>
> +
> +#include <efi.h>
> +
> +#include "disk.h"
>  #include "efiboot.h"
>  #include "efidev.h"
>  #include "efipxe.h"
> +#include "softraid_arm64.h"
>  
>  const char version[] = "0.13";
>  int  debug = 0;
> @@ -52,6 +61,7 @@ int nfsys = nitems(file_system);
>  struct devsw devsw[] = {
>       { "tftp", tftpstrategy, tftpopen, tftpclose, tftpioctl },
>       { "sd", efistrategy, efiopen, eficlose, efiioctl },
> +     { "sr", srstrategy, sropen, srclose, srioctl },
>  };
>  int ndevs = nitems(devsw);
>  
> diff --git sys/arch/arm64/stand/efiboot/disk.h 
> sys/arch/arm64/stand/efiboot/disk.h
> index 4007259da32..2a6bf3db93f 100644
> --- sys/arch/arm64/stand/efiboot/disk.h
> +++ sys/arch/arm64/stand/efiboot/disk.h
> @@ -3,6 +3,8 @@
>  #ifndef _DISK_H
>  #define _DISK_H
>  
> +#include <sys/queue.h>
> +
>  typedef struct efi_diskinfo {
>       EFI_BLOCK_IO            *blkio;
>       UINT32                   mediaid;
> @@ -11,10 +13,21 @@ typedef struct efi_diskinfo {
>  struct diskinfo {
>       struct efi_diskinfo ed;
>       struct disklabel disklabel;
> +     struct sr_boot_volume *sr_vol;
> +
> +     u_int part;
> +     u_int flags;
> +#define DISKINFO_FLAG_GOODLABEL              (1 << 0)
>  
> -     u_int sc_part;
> +     int (*diskio)(int, struct diskinfo *, u_int, int, void *);
> +     int (*strategy)(void *, int, daddr32_t, size_t, void *, size_t *);
> +
> +     TAILQ_ENTRY(diskinfo) list;
>  };
> +TAILQ_HEAD(disklist_lh, diskinfo);
> +
> +extern struct diskinfo *bootdev_dip;
>  
> -extern struct diskinfo diskinfo;
> +extern struct disklist_lh disklist;
>  
>  #endif /* _DISK_H */
> diff --git sys/arch/arm64/stand/efiboot/efiboot.c 
> sys/arch/arm64/stand/efiboot/efiboot.c
> index 4dc9d7e32fa..f3045639d91 100644
> --- sys/arch/arm64/stand/efiboot/efiboot.c
> +++ sys/arch/arm64/stand/efiboot/efiboot.c
> @@ -28,14 +28,21 @@
>  #include <efiprot.h>
>  #include <eficonsctl.h>
>  
> +#include <dev/biovar.h>
> +#include <dev/softraidvar.h>
> +
>  #include <lib/libkern/libkern.h>
> +#include <lib/libsa/softraid.h>
>  #include <stand/boot/cmd.h>
>  
> +#include "libsa.h"
>  #include "disk.h"
> +#include "softraid_arm64.h"
> +
> +#include "efidev.h"
>  #include "efiboot.h"
>  #include "eficall.h"
>  #include "fdt.h"
> -#include "libsa.h"
>  
>  EFI_SYSTEM_TABLE     *ST;
>  EFI_BOOT_SERVICES    *BS;
> @@ -173,19 +180,23 @@ efi_heap_init(void)
>               panic("BS->AllocatePages()");
>  }
>  
> -EFI_BLOCK_IO *disk;
> +struct disklist_lh disklist;
> +struct diskinfo *bootdev_dip;
>  
>  void
>  efi_diskprobe(void)
>  {
> -     int                      i, depth = -1;
> +     int                      i, bootdev = 0, depth = -1;
>       UINTN                    sz;
>       EFI_STATUS               status;
>       EFI_HANDLE              *handles = NULL;
>       EFI_BLOCK_IO            *blkio;
>       EFI_BLOCK_IO_MEDIA      *media;
> +     struct diskinfo         *di;
>       EFI_DEVICE_PATH         *dp;
>  
> +     TAILQ_INIT(&disklist);
> +
>       sz = 0;
>       status = EFI_CALL(BS->LocateHandle, ByProtocol, &blkio_guid, 0, &sz, 0);
>       if (status == EFI_BUFFER_TOO_SMALL) {
> @@ -217,20 +228,36 @@ efi_diskprobe(void)
>               media = blkio->Media;
>               if (media->LogicalPartition || !media->MediaPresent)
>                       continue;
> +             di = alloc(sizeof(struct diskinfo));
> +             efid_init(di, blkio);
>  
> -             if (efi_bootdp == NULL || depth == -1)
> -                     continue;
> +             if (efi_bootdp == NULL || depth == -1 || bootdev != 0)
> +                     goto next;
>               status = EFI_CALL(BS->HandleProtocol, handles[i], &devp_guid,
>                   (void **)&dp);
>               if (EFI_ERROR(status))
> -                     continue;
> +                     goto next;
>               if (efi_device_path_ncmp(efi_bootdp, dp, depth) == 0) {
> -                     disk = blkio;
> -                     break;
> +                     TAILQ_INSERT_HEAD(&disklist, di, list);
> +                     bootdev_dip = di;
> +                     bootdev = 1;
> +                     continue;
>               }
> +next:
> +             TAILQ_INSERT_TAIL(&disklist, di, list);
>       }
>  
>       free(handles, sz);
> +
> +     /* Print available disks and probe for softraid. */
> +     i = 0;
> +     printf("disks:");
> +     TAILQ_FOREACH(di, &disklist, list) {
> +             printf(" sd%d%s", i, di == bootdev_dip ? "*" : "");
> +             i++;
> +     }
> +     srprobe();
> +     printf("\n");
>  }
>  
>  /*
> @@ -370,6 +397,7 @@ static EFI_GUID fdt_guid = FDT_TABLE_GUID;
>  void *
>  efi_makebootargs(char *bootargs)
>  {
> +     struct sr_boot_volume *bv;
>       u_char bootduid[8];
>       u_char zero[8] = { 0 };
>       uint64_t uefi_system_table = htobe64((uintptr_t)ST);
> @@ -399,12 +427,27 @@ efi_makebootargs(char *bootargs)
>       fdt_node_add_property(node, "bootargs", bootargs, len);
>  
>       /* Pass DUID of the boot disk. */
> -     memcpy(&bootduid, diskinfo.disklabel.d_uid, sizeof(bootduid));
> -     if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) {
> -             fdt_node_add_property(node, "openbsd,bootduid", bootduid,
> +     if (bootdev_dip) {
> +             memcpy(&bootduid, bootdev_dip->disklabel.d_uid,
>                   sizeof(bootduid));
> +             if (memcmp(bootduid, zero, sizeof(bootduid)) != 0) {
> +                     fdt_node_add_property(node, "openbsd,bootduid",
> +                         bootduid, sizeof(bootduid));
> +             }
> +
> +             if (bootdev_dip->sr_vol != NULL) {
> +                     bv = bootdev_dip->sr_vol;
> +                     fdt_node_add_property(node, "openbsd,bootsr-uuid",
> +                         &bv->sbv_uuid, sizeof(bv->sbv_uuid));
> +                     if (bv->sbv_maskkey != NULL)
> +                             fdt_node_add_property(node,
> +                                 "openbsd,bootsr-maskkey", bv->sbv_maskkey,
> +                                 SR_CRYPTO_MAXKEYBYTES);
> +             }
>       }
>  
> +     sr_clear_keys();
> +
>       /* Pass netboot interface address. */
>       if (bootmac)
>               fdt_node_add_property(node, "openbsd,bootmac", bootmac, 6);
> @@ -558,10 +601,51 @@ getsecs(void)
>  void
>  devboot(dev_t dev, char *p)
>  {
> -     if (disk)
> -             strlcpy(p, "sd0a", 5);
> -     else
> +     struct sr_boot_volume *bv;
> +     struct sr_boot_chunk *bc;
> +     struct diskinfo *dip;
> +     int sd_boot_vol = 0;
> +     int sr_boot_vol = -1;
> +     int part_type = FS_UNUSED;
> +
> +     if (bootdev_dip == NULL) {
>               strlcpy(p, "tftp0a", 7);
> +             return;
> +     }
> +
> +     TAILQ_FOREACH(dip, &disklist, list) {
> +             if (bootdev_dip == dip)
> +                     break;
> +             sd_boot_vol++;
> +     }
> +
> +     /*
> +      * Determine the partition type for the 'a' partition of the
> +      * boot device.
> +      */
> +     if ((bootdev_dip->flags & DISKINFO_FLAG_GOODLABEL) != 0)
> +             part_type = bootdev_dip->disklabel.d_partitions[0].p_fstype;
> +
> +     /*
> +      * See if we booted from a disk that is a member of a bootable
> +      * softraid volume.
> +      */
> +     SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
> +             SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
> +                     if (bc->sbc_diskinfo == bootdev_dip)
> +                             sr_boot_vol = bv->sbv_unit;
> +             if (sr_boot_vol != -1)
> +                     break;
> +     }
> +
> +     if (sr_boot_vol != -1 && part_type != FS_BSDFFS) {
> +             strlcpy(p, "sr0a", 5);
> +             p[2] = '0' + sr_boot_vol;
> +             return;
> +     }
> +
> +     strlcpy(p, "sd0a", 5);
> +     p[2] = '0' + sd_boot_vol;
>  }
>  
>  int
> diff --git sys/arch/arm64/stand/efiboot/efidev.c 
> sys/arch/arm64/stand/efiboot/efidev.c
> index 91c1ce5f90d..3cd4fac874b 100644
> --- sys/arch/arm64/stand/efiboot/efidev.c
> +++ sys/arch/arm64/stand/efiboot/efidev.c
> @@ -48,17 +48,30 @@ extern int debug;
>  #define EFI_BLKSPERSEC(_ed)  ((_ed)->blkio->Media->BlockSize / DEV_BSIZE)
>  #define EFI_SECTOBLK(_ed, _n)        ((_n) * EFI_BLKSPERSEC(_ed))
>  
> -extern EFI_BLOCK_IO *disk;
> -struct diskinfo diskinfo;
> -
>  static EFI_STATUS
>                efid_io(int, efi_diskinfo_t, u_int, int, void *);
>  static int    efid_diskio(int, struct diskinfo *, u_int, int, void *);
> +const char *  efi_getdisklabel(efi_diskinfo_t, struct disklabel *);
>  static int    efi_getdisklabel_cd9660(efi_diskinfo_t, struct disklabel *);
>  static u_int  findopenbsd(efi_diskinfo_t, const char **);
>  static u_int  findopenbsd_gpt(efi_diskinfo_t, const char **);
>  static int    gpt_chk_mbr(struct dos_partition *, u_int64_t);
>  
> +void
> +efid_init(struct diskinfo *dip, void *handle)
> +{
> +     EFI_BLOCK_IO            *blkio = handle;
> +
> +     memset(dip, 0, sizeof(struct diskinfo));
> +     dip->ed.blkio = blkio;
> +     dip->ed.mediaid = blkio->Media->MediaId;
> +     dip->diskio = efid_diskio;
> +     dip->strategy = efistrategy;
> +
> +     if (efi_getdisklabel(&dip->ed, &dip->disklabel) == NULL)
> +             dip->flags |= DISKINFO_FLAG_GOODLABEL;
> +}
> +
>  static EFI_STATUS
>  efid_io(int rw, efi_diskinfo_t ed, u_int off, int nsect, void *buf)
>  {
> @@ -471,32 +484,33 @@ efi_getdisklabel_cd9660(efi_diskinfo_t ed, struct 
> disklabel *label)
>  int
>  efiopen(struct open_file *f, ...)
>  {
> -     struct diskinfo *dip = &diskinfo;
> +     struct diskinfo *dip = NULL;
>       va_list ap;
>       u_int unit, part;
> -     const char *err;
> -
> -     if (disk == NULL)
> -             return (ENXIO);
> +     int i = 0;
>  
>       va_start(ap, f);
>       unit = va_arg(ap, u_int);
>       part = va_arg(ap, u_int);
>       va_end(ap);
>  
> -     if (unit != 0 || part >= MAXPARTITIONS)
> +     if (part >= MAXPARTITIONS)
>               return (ENXIO);
>  
> -     diskinfo.ed.blkio = disk;
> -     diskinfo.ed.mediaid = disk->Media->MediaId;
> -     diskinfo.sc_part = part;
> -
> -     err = efi_getdisklabel(&dip->ed, &dip->disklabel);
> -     if (err) {
> -             printf("%s\n", err);
> -             return EINVAL;
> +     TAILQ_FOREACH(dip, &disklist, list) {
> +             if (i == unit)
> +                     break;
> +             i++;
>       }
>  
> +     if (dip == NULL)
> +             return (ENXIO);
> +
> +     if ((dip->flags & DISKINFO_FLAG_GOODLABEL) == 0)
> +             return (ENXIO);
> +
> +     dip->part = part;
> +     bootdev_dip = dip;
>       f->f_devdata = dip;
>  
>       return 0;
> @@ -512,7 +526,7 @@ efistrategy(void *devdata, int rw, daddr32_t blk, size_t 
> size, void *buf,
>  
>       nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE;
>       blk += DL_SECTOBLK(&dip->disklabel,
> -         dip->disklabel.d_partitions[dip->sc_part].p_offset);
> +         dip->disklabel.d_partitions[dip->part].p_offset);
>  
>       if (blk < 0)
>               error = EINVAL;
> diff --git sys/arch/arm64/stand/efiboot/efidev.h 
> sys/arch/arm64/stand/efiboot/efidev.h
> index a771bfcc1f7..95a09463ab5 100644
> --- sys/arch/arm64/stand/efiboot/efidev.h
> +++ sys/arch/arm64/stand/efiboot/efidev.h
> @@ -29,6 +29,7 @@
>   */
>  
>  /* efidev.c */
> +void          efid_init(struct diskinfo *, void *handle);
>  int           efiopen(struct open_file *, ...);
>  int           efistrategy(void *, int, daddr32_t, size_t, void *, size_t *);
>  int           eficlose(struct open_file *);
> diff --git sys/arch/arm64/stand/efiboot/softraid_arm64.c 
> sys/arch/arm64/stand/efiboot/softraid_arm64.c
> new file mode 100644
> index 00000000000..693198d2357
> --- /dev/null
> +++ sys/arch/arm64/stand/efiboot/softraid_arm64.c
> @@ -0,0 +1,665 @@
> +/*   $OpenBSD: softraid_amd64.c,v 1.5 2017/12/18 12:53:33 fcambus Exp $      
> */
> +
> +/*
> + * Copyright (c) 2012 Joel Sing <[email protected]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#include <sys/param.h>
> +#include <sys/queue.h>
> +#include <sys/disklabel.h>
> +#include <sys/reboot.h>
> +
> +#include <dev/biovar.h>
> +#include <dev/softraidvar.h>
> +
> +#include <lib/libsa/aes_xts.h>
> +#include <lib/libsa/softraid.h>
> +#include <lib/libz/zlib.h>
> +
> +#include <efi.h>
> +
> +#include "libsa.h"
> +#include "disk.h"
> +#include "efidev.h"
> +#include "softraid_arm64.h"
> +
> +static int gpt_chk_mbr(struct dos_partition *, u_int64_t);
> +static uint64_t findopenbsd_gpt(struct sr_boot_volume *, const char **);
> +
> +void
> +srprobe_meta_opt_load(struct sr_metadata *sm, struct sr_meta_opt_head *som)
> +{
> +     struct sr_meta_opt_hdr  *omh;
> +     struct sr_meta_opt_item *omi;
> +#if 0
> +     u_int8_t checksum[MD5_DIGEST_LENGTH];
> +#endif
> +     int                     i;
> +
> +     /* Process optional metadata. */
> +     omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) +
> +         sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
> +     for (i = 0; i < sm->ssdi.ssd_opt_no; i++) {
> +
> +#ifdef BIOS_DEBUG
> +             printf("Found optional metadata of type %u, length %u\n",
> +                 omh->som_type, omh->som_length);
> +#endif
> +
> +             /* Unsupported old fixed length optional metadata. */
> +             if (omh->som_length == 0) {
> +                     omh = (struct sr_meta_opt_hdr *)((void *)omh +
> +                         SR_OLD_META_OPT_SIZE);
> +                     continue;
> +             }
> +
> +             /* Load variable length optional metadata. */
> +             omi = alloc(sizeof(struct sr_meta_opt_item));
> +             bzero(omi, sizeof(struct sr_meta_opt_item));
> +             SLIST_INSERT_HEAD(som, omi, omi_link);
> +             omi->omi_som = alloc(omh->som_length);
> +             bzero(omi->omi_som, omh->som_length);
> +             bcopy(omh, omi->omi_som, omh->som_length);
> +
> +#if 0
> +             /* XXX - Validate checksum. */
> +             bcopy(&omi->omi_som->som_checksum, &checksum,
> +                 MD5_DIGEST_LENGTH);
> +             bzero(&omi->omi_som->som_checksum, MD5_DIGEST_LENGTH);
> +             sr_checksum(sc, omi->omi_som,
> +                 &omi->omi_som->som_checksum, omh->som_length);
> +             if (bcmp(&checksum, &omi->omi_som->som_checksum,
> +                 sizeof(checksum)))
> +                     panic("%s: invalid optional metadata checksum",
> +                         DEVNAME(sc));
> +#endif
> +
> +             omh = (struct sr_meta_opt_hdr *)((void *)omh +
> +                 omh->som_length);
> +     }
> +}
> +
> +void
> +srprobe_keydisk_load(struct sr_metadata *sm)
> +{
> +     struct sr_meta_opt_hdr  *omh;
> +     struct sr_meta_keydisk  *skm;
> +     struct sr_boot_keydisk  *kd;
> +     int i;
> +
> +     /* Process optional metadata. */
> +     omh = (struct sr_meta_opt_hdr *)((u_int8_t *)(sm + 1) +
> +         sizeof(struct sr_meta_chunk) * sm->ssdi.ssd_chunk_no);
> +     for (i = 0; i < sm->ssdi.ssd_opt_no; i++) {
> +
> +             /* Unsupported old fixed length optional metadata. */
> +             if (omh->som_length == 0) {
> +                     omh = (struct sr_meta_opt_hdr *)((void *)omh +
> +                         SR_OLD_META_OPT_SIZE);
> +                     continue;
> +             }
> +
> +             if (omh->som_type != SR_OPT_KEYDISK) {
> +                     omh = (struct sr_meta_opt_hdr *)((void *)omh +
> +                         omh->som_length);
> +                     continue;
> +             }
> +
> +             kd = alloc(sizeof(struct sr_boot_keydisk));
> +             bcopy(&sm->ssdi.ssd_uuid, &kd->kd_uuid, sizeof(kd->kd_uuid));
> +             skm = (struct sr_meta_keydisk*)omh;
> +             bcopy(&skm->skm_maskkey, &kd->kd_key, sizeof(kd->kd_key));
> +             SLIST_INSERT_HEAD(&sr_keydisks, kd, kd_link);
> +     }
> +}
> +
> +void
> +srprobe(void)
> +{
> +     struct sr_boot_volume *bv, *bv1, *bv2;
> +     struct sr_boot_chunk *bc, *bc1, *bc2;
> +     struct sr_meta_chunk *mc;
> +     struct sr_metadata *md;
> +     struct diskinfo *dip;
> +     struct partition *pp;
> +     int i, error, volno;
> +     daddr_t off;
> +
> +     /* Probe for softraid volumes. */
> +     SLIST_INIT(&sr_volumes);
> +     SLIST_INIT(&sr_keydisks);
> +
> +     md = alloc(SR_META_SIZE * DEV_BSIZE);
> +
> +     TAILQ_FOREACH(dip, &disklist, list) {
> +
> +             /* Make sure disklabel has been read. */
> +             if ((dip->flags & DISKINFO_FLAG_GOODLABEL) == 0)
> +                     continue;
> +
> +             for (i = 0; i < MAXPARTITIONS; i++) {
> +
> +                     pp = &dip->disklabel.d_partitions[i];
> +                     if (pp->p_fstype != FS_RAID || pp->p_size == 0)
> +                             continue;
> +
> +                     /* Read softraid metadata. */
> +                     bzero(md, SR_META_SIZE * DEV_BSIZE);
> +                     off = DL_SECTOBLK(&dip->disklabel, DL_GETPOFFSET(pp));
> +                     off += SR_META_OFFSET;
> +                     error = dip->diskio(F_READ, dip, off, SR_META_SIZE, md);
> +                     if (error)
> +                             continue;
> +
> +                     /* Is this valid softraid metadata? */
> +                     if (md->ssdi.ssd_magic != SR_MAGIC)
> +                             continue;
> +
> +                     /* XXX - validate checksum. */
> +
> +                     /* Handle key disks separately... */
> +                     if (md->ssdi.ssd_level == SR_KEYDISK_LEVEL) {
> +                             srprobe_keydisk_load(md);
> +                             continue;
> +                     }
> +
> +                     /* Locate chunk-specific metadata for this chunk. */
> +                     mc = (struct sr_meta_chunk *)(md + 1);
> +                     mc += md->ssdi.ssd_chunk_id;
> +
> +                     bc = alloc(sizeof(struct sr_boot_chunk));
> +                     bc->sbc_diskinfo = dip;
> +                     bc->sbc_disk = 0;
> +                     bc->sbc_part = 'a' + i;
> +
> +                     bc->sbc_mm = 0;
> +
> +                     bc->sbc_chunk_id = md->ssdi.ssd_chunk_id;
> +                     bc->sbc_ondisk = md->ssd_ondisk;
> +                     bc->sbc_state = mc->scm_status;
> +
> +                     SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
> +                             if (bcmp(&md->ssdi.ssd_uuid, &bv->sbv_uuid,
> +                                 sizeof(md->ssdi.ssd_uuid)) == 0)
> +                                     break;
> +                     }
> +
> +                     if (bv == NULL) {
> +                             bv = alloc(sizeof(struct sr_boot_volume));
> +                             bzero(bv, sizeof(struct sr_boot_volume));
> +                             bv->sbv_level = md->ssdi.ssd_level;
> +                             bv->sbv_volid = md->ssdi.ssd_volid;
> +                             bv->sbv_chunk_no = md->ssdi.ssd_chunk_no;
> +                             bv->sbv_flags = md->ssdi.ssd_vol_flags;
> +                             bv->sbv_size = md->ssdi.ssd_size;
> +                             bv->sbv_secsize = md->ssdi.ssd_secsize;
> +                             bv->sbv_data_blkno = md->ssd_data_blkno;
> +                             bcopy(&md->ssdi.ssd_uuid, &bv->sbv_uuid,
> +                                 sizeof(md->ssdi.ssd_uuid));
> +                             SLIST_INIT(&bv->sbv_chunks);
> +                             SLIST_INIT(&bv->sbv_meta_opt);
> +
> +                             /* Load optional metadata for this volume. */
> +                             srprobe_meta_opt_load(md, &bv->sbv_meta_opt);
> +
> +                             /* Maintain volume order. */
> +                             bv2 = NULL;
> +                             SLIST_FOREACH(bv1, &sr_volumes, sbv_link) {
> +                                     if (bv1->sbv_volid > bv->sbv_volid)
> +                                             break;
> +                                     bv2 = bv1;
> +                             }
> +                             if (bv2 == NULL)
> +                                     SLIST_INSERT_HEAD(&sr_volumes, bv,
> +                                         sbv_link);
> +                             else
> +                                     SLIST_INSERT_AFTER(bv2, bv, sbv_link);
> +                     }
> +
> +                     /* Maintain chunk order. */
> +                     bc2 = NULL;
> +                     SLIST_FOREACH(bc1, &bv->sbv_chunks, sbc_link) {
> +                             if (bc1->sbc_chunk_id > bc->sbc_chunk_id)
> +                                     break;
> +                             bc2 = bc1;
> +                     }
> +                     if (bc2 == NULL)
> +                             SLIST_INSERT_HEAD(&bv->sbv_chunks,
> +                                 bc, sbc_link);
> +                     else
> +                             SLIST_INSERT_AFTER(bc2, bc, sbc_link);
> +
> +                     bv->sbv_chunks_found++;
> +             }
> +     }
> +
> +     /*
> +      * Assemble RAID volumes.
> +      */
> +     volno = 0;
> +     SLIST_FOREACH(bv, &sr_volumes, sbv_link) {
> +
> +             /* Skip if this is a hotspare "volume". */
> +             if (bv->sbv_level == SR_HOTSPARE_LEVEL &&
> +                 bv->sbv_chunk_no == 1)
> +                     continue;
> +
> +             /* Determine current ondisk version. */
> +             bv->sbv_ondisk = 0;
> +             SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) {
> +                     if (bc->sbc_ondisk > bv->sbv_ondisk)
> +                             bv->sbv_ondisk = bc->sbc_ondisk;
> +             }
> +             SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link) {
> +                     if (bc->sbc_ondisk != bv->sbv_ondisk)
> +                             bc->sbc_state = BIOC_SDOFFLINE;
> +             }
> +
> +             /* XXX - Check for duplicate chunks. */
> +
> +             /*
> +              * Validate that volume has sufficient chunks for
> +              * read-only access.
> +              *
> +              * XXX - check chunk states.
> +              */
> +             bv->sbv_state = BIOC_SVOFFLINE;
> +             switch (bv->sbv_level) {
> +             case 0:
> +             case 'C':
> +             case 'c':
> +                     if (bv->sbv_chunk_no == bv->sbv_chunks_found)
> +                             bv->sbv_state = BIOC_SVONLINE;
> +                     break;
> +
> +             case 1:
> +                     if (bv->sbv_chunk_no == bv->sbv_chunks_found)
> +                             bv->sbv_state = BIOC_SVONLINE;
> +                     else if (bv->sbv_chunks_found > 0)
> +                             bv->sbv_state = BIOC_SVDEGRADED;
> +                     break;
> +             }
> +
> +             bv->sbv_unit = volno++;
> +             if (bv->sbv_state != BIOC_SVOFFLINE)
> +                     printf(" sr%d%s", bv->sbv_unit,
> +                         bv->sbv_flags & BIOC_SCBOOTABLE ? "*" : "");
> +     }
> +
> +     explicit_bzero(md, SR_META_SIZE * DEV_BSIZE);
> +     free(md, SR_META_SIZE * DEV_BSIZE);
> +}
> +
> +int
> +sr_strategy(struct sr_boot_volume *bv, int rw, daddr32_t blk, size_t size,
> +    void *buf, size_t *rsize)
> +{
> +     struct diskinfo *sr_dip, *dip;
> +     struct sr_boot_chunk *bc;
> +     struct aes_xts_ctx ctx;
> +     size_t i, j, nsect;
> +     daddr_t blkno;
> +     u_char iv[8];
> +     u_char *bp;
> +     int err;
> +
> +     /* We only support read-only softraid. */
> +     if (rw != F_READ)
> +             return ENOTSUP;
> +
> +     /* Partition offset within softraid volume. */
> +     sr_dip = (struct diskinfo *)bv->sbv_diskinfo;
> +     blk += DL_SECTOBLK(&sr_dip->disklabel,
> +         sr_dip->disklabel.d_partitions[bv->sbv_part - 'a'].p_offset);
> +
> +     if (bv->sbv_level == 0) {
> +             return ENOTSUP;
> +     } else if (bv->sbv_level == 1) {
> +
> +             /* Select first online chunk. */
> +             SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
> +                     if (bc->sbc_state == BIOC_SDONLINE)
> +                             break;
> +             if (bc == NULL)
> +                     return EIO;
> +
> +             dip = (struct diskinfo *)bc->sbc_diskinfo;
> +             blk += bv->sbv_data_blkno;
> +
> +             /* XXX - If I/O failed we should try another chunk... */
> +             return dip->strategy(dip, rw, blk, size, buf, rsize);
> +
> +     } else if (bv->sbv_level == 'C') {
> +
> +             /* Select first online chunk. */
> +             SLIST_FOREACH(bc, &bv->sbv_chunks, sbc_link)
> +                     if (bc->sbc_state == BIOC_SDONLINE)
> +                             break;
> +             if (bc == NULL)
> +                     return EIO;
> +
> +             dip = (struct diskinfo *)bc->sbc_diskinfo;
> +
> +             /* XXX - select correct key. */
> +             aes_xts_setkey(&ctx, (u_char *)bv->sbv_keys, 64);
> +
> +             nsect = (size + DEV_BSIZE - 1) / DEV_BSIZE;
> +             for (i = 0; i < nsect; i++) {
> +                     blkno = blk + i;
> +                     bp = ((u_char *)buf) + i * DEV_BSIZE;
> +                     err = dip->strategy(dip, rw, bv->sbv_data_blkno + blkno,
> +                         DEV_BSIZE, bp, NULL);
> +                     if (err != 0)
> +                             return err;
> +
> +                     bcopy(&blkno, iv, sizeof(blkno));
> +                     aes_xts_reinit(&ctx, iv);
> +                     for (j = 0; j < DEV_BSIZE; j += AES_XTS_BLOCKSIZE)
> +                             aes_xts_decrypt(&ctx, bp + j);
> +             }
> +             if (rsize != NULL)
> +                     *rsize = nsect * DEV_BSIZE;
> +
> +             return err;
> +
> +     } else
> +             return ENOTSUP;
> +}
> +
> +/*
> + * Returns 0 if the MBR with the provided partition array is a GPT protective
> + * MBR, and returns 1 otherwise. A GPT protective MBR would have one and only
> + * one MBR partition, an EFI partition that either covers the whole disk or 
> as
> + * much of it as is possible with a 32bit size field.
> + *
> + * Taken from kern/subr_disk.c.
> + *
> + * NOTE: MS always uses a size of UINT32_MAX for the EFI partition!**
> + */
> +static int
> +gpt_chk_mbr(struct dos_partition *dp, u_int64_t dsize)
> +{
> +     struct dos_partition *dp2;
> +     int efi, found, i;
> +     u_int32_t psize;
> +
> +     found = efi = 0;
> +     for (dp2=dp, i=0; i < NDOSPART; i++, dp2++) {
> +             if (dp2->dp_typ == DOSPTYP_UNUSED)
> +                     continue;
> +             found++;
> +             if (dp2->dp_typ != DOSPTYP_EFI)
> +                     continue;
> +             psize = letoh32(dp2->dp_size);
> +             if (psize == (dsize - 1) ||
> +                 psize == UINT32_MAX) {
> +                     if (letoh32(dp2->dp_start) == 1)
> +                             efi++;
> +             }
> +     }
> +     if (found == 1 && efi == 1)
> +             return (0);
> +
> +     return (1);
> +}
> +
> +static uint64_t
> +findopenbsd_gpt(struct sr_boot_volume *bv, const char **err)
> +{
> +     struct                   gpt_header gh;
> +     int                      i, part, found;
> +     uint64_t                 lba;
> +     uint32_t                 orig_csum, new_csum;
> +     uint32_t                 ghsize, ghpartsize, ghpartnum, ghpartspersec;
> +     uint32_t                 gpsectors;
> +     const char               openbsd_uuid_code[] = GPT_UUID_OPENBSD;
> +     struct gpt_partition     gp;
> +     static struct uuid      *openbsd_uuid = NULL, openbsd_uuid_space;
> +     u_char                  *buf;
> +
> +     /* Prepare OpenBSD UUID */
> +     if (openbsd_uuid == NULL) {
> +             /* XXX: should be replaced by uuid_dec_be() */
> +             memcpy(&openbsd_uuid_space, openbsd_uuid_code,
> +                 sizeof(openbsd_uuid_space));
> +             openbsd_uuid_space.time_low =
> +                 betoh32(openbsd_uuid_space.time_low);
> +             openbsd_uuid_space.time_mid =
> +                 betoh16(openbsd_uuid_space.time_mid);
> +             openbsd_uuid_space.time_hi_and_version =
> +                 betoh16(openbsd_uuid_space.time_hi_and_version);
> +
> +             openbsd_uuid = &openbsd_uuid_space;
> +     }
> +
> +     if (bv->sbv_secsize > 4096) {
> +             *err = "disk sector > 4096 bytes\n";
> +             return (-1);
> +     }
> +     buf = alloc(bv->sbv_secsize);
> +     if (buf == NULL) {
> +             *err = "out of memory\n";
> +             return (-1);
> +     }
> +     bzero(buf, bv->sbv_secsize);
> +
> +     /* LBA1: GPT Header */
> +     lba = 1;
> +     sr_strategy(bv, F_READ, lba * (bv->sbv_secsize / DEV_BSIZE), DEV_BSIZE,
> +         buf, NULL);
> +     memcpy(&gh, buf, sizeof(gh));
> +
> +     /* Check signature */
> +     if (letoh64(gh.gh_sig) != GPTSIGNATURE) {
> +             *err = "bad GPT signature\n";
> +             free(buf, bv->sbv_secsize);
> +             return (-1);
> +     }
> +
> +     if (letoh32(gh.gh_rev) != GPTREVISION) {
> +             *err = "bad GPT revision\n";
> +             free(buf, bv->sbv_secsize);
> +             return (-1);
> +     }
> +
> +     ghsize = letoh32(gh.gh_size);
> +     if (ghsize < GPTMINHDRSIZE || ghsize > sizeof(struct gpt_header)) {
> +             *err = "bad GPT header size\n";
> +             free(buf, bv->sbv_secsize);
> +             return (-1);
> +     }
> +
> +     /* Check checksum */
> +     orig_csum = gh.gh_csum;
> +     gh.gh_csum = 0;
> +     new_csum = crc32(0, (unsigned char *)&gh, ghsize);
> +     gh.gh_csum = orig_csum;
> +     if (letoh32(orig_csum) != new_csum) {
> +             *err = "bad GPT header checksum\n";
> +             free(buf, bv->sbv_secsize);
> +             return (-1);
> +     }
> +
> +     lba = letoh64(gh.gh_part_lba);
> +     ghpartsize = letoh32(gh.gh_part_size);
> +     ghpartspersec = bv->sbv_secsize / ghpartsize;
> +     ghpartnum = letoh32(gh.gh_part_num);
> +     gpsectors = (ghpartnum + ghpartspersec - 1) / ghpartspersec;
> +     new_csum = crc32(0L, Z_NULL, 0);
> +     found = 0;
> +     for (i = 0; i < gpsectors; i++, lba++) {
> +             sr_strategy(bv, F_READ, lba * (bv->sbv_secsize / DEV_BSIZE),
> +                 bv->sbv_secsize, buf, NULL);
> +             for (part = 0; part < ghpartspersec; part++) {
> +                     if (ghpartnum == 0)
> +                             break;
> +                     new_csum = crc32(new_csum, buf + part * sizeof(gp),
> +                         sizeof(gp));
> +                     ghpartnum--;
> +                     if (found)
> +                             continue;
> +                     memcpy(&gp, buf + part * sizeof(gp), sizeof(gp));
> +                     if (memcmp(&gp.gp_type, openbsd_uuid,
> +                         sizeof(struct uuid)) == 0)
> +                             found = 1;
> +             }
> +     }
> +
> +     free(buf, bv->sbv_secsize);
> +
> +     if (new_csum != letoh32(gh.gh_part_csum)) {
> +             *err = "bad GPT entries checksum\n";
> +             return (-1);
> +     }
> +     if (found)
> +             return (letoh64(gp.gp_lba_start));
> +
> +     return (-1);
> +}
> +
> +const char *
> +sr_getdisklabel(struct sr_boot_volume *bv, struct disklabel *label)
> +{
> +     struct dos_partition *dp;
> +     struct dos_mbr mbr;
> +     const char *err = NULL;
> +     u_int start = 0;
> +     char buf[DEV_BSIZE];
> +     int i;
> +
> +     /* Check for MBR to determine partition offset. */
> +     bzero(&mbr, sizeof(mbr));
> +     sr_strategy(bv, F_READ, DOSBBSECTOR, sizeof(mbr), &mbr, NULL);
> +     if (gpt_chk_mbr(mbr.dmbr_parts, bv->sbv_size /
> +                 (bv->sbv_secsize / DEV_BSIZE)) == 0) {
> +             start = findopenbsd_gpt(bv, &err);
> +             if (start == (u_int)-1) {
> +                     if (err != NULL)
> +                             return (err);
> +                     return "no OpenBSD partition\n";
> +             }
> +     } else if (mbr.dmbr_sign == DOSMBR_SIGNATURE) {
> +
> +             /* Search for OpenBSD partition */
> +             for (i = 0; i < NDOSPART; i++) {
> +                     dp = &mbr.dmbr_parts[i];
> +                     if (!dp->dp_size)
> +                             continue;
> +                     if (dp->dp_typ == DOSPTYP_OPENBSD) {
> +                             start = dp->dp_start;
> +                             break;
> +                     }
> +             }
> +     }
> +
> +     /* Read the disklabel. */
> +     sr_strategy(bv, F_READ,
> +         start * (bv->sbv_secsize / DEV_BSIZE) + DOS_LABELSECTOR,
> +         sizeof(struct disklabel), buf, NULL);
> +
> +#ifdef BIOS_DEBUG
> +     printf("sr_getdisklabel: magic %lx\n",
> +         ((struct disklabel *)buf)->d_magic);
> +     for (i = 0; i < MAXPARTITIONS; i++)
> +             printf("part %c: type = %d, size = %d, offset = %d\n", 'a' + i,
> +                 (int)((struct disklabel *)buf)->d_partitions[i].p_fstype,
> +                 (int)((struct disklabel *)buf)->d_partitions[i].p_size,
> +                 (int)((struct disklabel *)buf)->d_partitions[i].p_offset);
> +#endif
> +
> +     /* Fill in disklabel */
> +     return (getdisklabel(buf, label));
> +}
> +
> +int
> +sropen(struct open_file *f, ...)
> +{
> +     struct diskinfo *dip = NULL;
> +     struct sr_boot_volume *bv;
> +     va_list ap;
> +     u_int unit, part;
> +
> +     va_start(ap, f);
> +     unit = va_arg(ap, u_int);
> +     part = va_arg(ap, u_int);
> +     va_end(ap);
> +
> +     /* Create a fake diskinfo for this softraid volume. */
> +     SLIST_FOREACH(bv, &sr_volumes, sbv_link)
> +             if (bv->sbv_unit == unit)
> +                     break;
> +     if (bv == NULL) {
> +             printf("Unknown device: sr%d\n", unit);
> +             return EADAPT;
> +     }
> +
> +     if (bv->sbv_level == 'C' && bv->sbv_keys == NULL)
> +             if (sr_crypto_unlock_volume(bv) != 0)
> +                     return EPERM;
> +
> +     if (bv->sbv_diskinfo == NULL) {
> +             dip = alloc(sizeof(struct diskinfo));
> +             bzero(dip, sizeof(*dip));
> +             dip->diskio = srdiskio;
> +             dip->strategy = srstrategy;
> +             bv->sbv_diskinfo = dip;
> +             dip->sr_vol = bv;
> +     }
> +
> +     dip = bv->sbv_diskinfo;
> +
> +     if ((dip->flags & DISKINFO_FLAG_GOODLABEL) == 0) {
> +             /* Attempt to read disklabel. */
> +             bv->sbv_part = 'c';
> +             if (sr_getdisklabel(bv, &dip->disklabel))
> +                     return ERDLAB;
> +             dip->flags |= DISKINFO_FLAG_GOODLABEL;
> +     }
> +
> +     bv->sbv_part = part + 'a';
> +
> +     bootdev_dip = dip;
> +     f->f_devdata = dip;
> +
> +     return 0;
> +}
> +
> +int
> +srstrategy(void *devdata, int rw, daddr32_t blk, size_t size, void *buf,
> +    size_t *rsize)
> +{
> +     struct diskinfo *dip = (struct diskinfo *)devdata;
> +     return sr_strategy(dip->sr_vol, rw, blk, size, buf, rsize);
> +}
> +
> +int
> +srdiskio(int rw, struct diskinfo *dip, u_int off, int nsect, void *buf)
> +{
> +     return dip->diskio(rw, dip, off, nsect, buf);
> +}
> +
> +int
> +srclose(struct open_file *f)
> +{
> +     f->f_devdata = NULL;
> +
> +     return 0;
> +}
> +
> +int
> +srioctl(struct open_file *f, u_long cmd, void *data)
> +{
> +     return 0;
> +}
> diff --git sys/arch/arm64/stand/efiboot/softraid_arm64.h 
> sys/arch/arm64/stand/efiboot/softraid_arm64.h
> new file mode 100644
> index 00000000000..bd6b0f6e4c3
> --- /dev/null
> +++ sys/arch/arm64/stand/efiboot/softraid_arm64.h
> @@ -0,0 +1,33 @@
> +/*   $OpenBSD: softraid_amd64.h,v 1.3 2016/09/11 17:51:21 jsing Exp $        
> */
> +
> +/*
> + * Copyright (c) 2012 Joel Sing <[email protected]>
> + *
> + * Permission to use, copy, modify, and distribute this software for any
> + * purpose with or without fee is hereby granted, provided that the above
> + * copyright notice and this permission notice appear in all copies.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
> + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
> + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
> + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
> + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
> + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
> + */
> +
> +#ifndef _SOFTRAID_ARM64_H_
> +#define _SOFTRAID_ARM64_H_
> +
> +void srprobe(void);
> +
> +const char *sr_getdisklabel(struct sr_boot_volume *, struct disklabel *);
> +int  sr_strategy(struct sr_boot_volume *, int, daddr32_t, size_t,
> +         void *, size_t *);
> +int  sropen(struct open_file *, ...);
> +int  srstrategy(void *, int, daddr32_t, size_t, void *, size_t *);
> +int  srdiskio(int, struct diskinfo *, u_int, int, void *);
> +int  srclose(struct open_file *);
> +int  srioctl(struct open_file *, u_long, void *);
> +
> +#endif /* _SOFTRAID_ARM64_H */
> 
> 

Reply via email to