-/* $OpenBSD: hibernate_machdep.c,v 1.26 2014/07/16 17:44:16 mlarkin Exp $ */
+/* $OpenBSD: hibernate_machdep.c,v 1.27 2014/07/20 18:05:21 mlarkin Exp $ */
/*
* Copyright (c) 2012 Mike Larkin <mlarkin@openbsd.org>
#include "acpi.h"
#include "wd.h"
#include "ahci.h"
+#include "softraid.h"
#include "sd.h"
/* Hibernate support */
* Returns the hibernate write I/O function to use on this machine
*/
hibio_fn
-get_hibernate_io_function(void)
+get_hibernate_io_function(dev_t dev)
{
- char *blkname = findblkname(major(swdevt[0].sw_dev));
+ char *blkname = findblkname(major(dev));
if (blkname == NULL)
return NULL;
return wd_hibernate_io;
}
#endif
-#if NAHCI > 0 && NSD > 0
+#if NSD > 0
if (strcmp(blkname, "sd") == 0) {
extern struct cfdriver sd_cd;
extern int ahci_hibernate_io(dev_t dev, daddr_t blkno,
vaddr_t addr, size_t size, int op, void *page);
+ extern int sr_hibernate_io(dev_t dev, daddr_t blkno,
+ vaddr_t addr, size_t size, int op, void *page);
struct device *dv;
+#if NAHCI > 0
dv = disk_lookup(&sd_cd, DISKUNIT(swdevt[0].sw_dev));
if (dv && dv->dv_parent && dv->dv_parent->dv_parent &&
strcmp(dv->dv_parent->dv_parent->dv_cfdata->cf_driver->cd_name,
"ahci") == 0)
return ahci_hibernate_io;
+#endif
+#if NSOFTRAID > 0
+ if (dv && dv->dv_parent && dv->dv_parent->dv_parent &&
+ strcmp(dv->dv_parent->dv_parent->dv_cfdata->cf_driver->cd_name,
+ "softraid") == 0)
+ return sr_hibernate_io;
}
#endif
+#endif /* NSD > 0 */
return NULL;
}
-/* $OpenBSD: hibernate_machdep.c,v 1.36 2014/07/16 17:44:16 mlarkin Exp $ */
+/* $OpenBSD: hibernate_machdep.c,v 1.37 2014/07/20 18:05:21 mlarkin Exp $ */
/*
* Copyright (c) 2011 Mike Larkin <mlarkin@openbsd.org>
#include "acpi.h"
#include "wd.h"
#include "ahci.h"
+#include "softraid.h"
#include "sd.h"
/* Hibernate support */
* Returns the hibernate write I/O function to use on this machine
*/
hibio_fn
-get_hibernate_io_function(void)
+get_hibernate_io_function(dev_t dev)
{
- char *blkname = findblkname(major(swdevt[0].sw_dev));
+ char *blkname = findblkname(major(dev));
if (blkname == NULL)
return NULL;
+
#if NWD > 0
if (strcmp(blkname, "wd") == 0) {
extern int wd_hibernate_io(dev_t dev, daddr_t blkno,
return wd_hibernate_io;
}
#endif
-#if NAHCI > 0 && NSD > 0
+#if NSD > 0
if (strcmp(blkname, "sd") == 0) {
extern struct cfdriver sd_cd;
extern int ahci_hibernate_io(dev_t dev, daddr_t blkno,
vaddr_t addr, size_t size, int op, void *page);
+ extern int sr_hibernate_io(dev_t dev, daddr_t blkno,
+ vaddr_t addr, size_t size, int op, void *page);
struct device *dv;
+#if NAHCI > 0
dv = disk_lookup(&sd_cd, DISKUNIT(swdevt[0].sw_dev));
if (dv && dv->dv_parent && dv->dv_parent->dv_parent &&
strcmp(dv->dv_parent->dv_parent->dv_cfdata->cf_driver->cd_name,
"ahci") == 0)
return ahci_hibernate_io;
+#endif
+#if NSOFTRAID > 0
+ if (dv && dv->dv_parent && dv->dv_parent->dv_parent &&
+ strcmp(dv->dv_parent->dv_parent->dv_cfdata->cf_driver->cd_name,
+ "softraid") == 0)
+ return sr_hibernate_io;
}
#endif
+#endif /* NSD > 0 */
return NULL;
}
-/* $OpenBSD: hibernate_machdep.c,v 1.5 2014/07/09 15:03:12 mlarkin Exp $ */
+/* $OpenBSD: hibernate_machdep.c,v 1.6 2014/07/20 18:05:21 mlarkin Exp $ */
/*
* Copyright (c) 2013 Paul Irofti.
#include "wd.h"
#include "ahci.h"
+#include "softraid.h"
#include "sd.h"
#if NWD > 0
#include <dev/ata/wdvar.h>
#endif
-
/*
* Loongson MD Hibernate functions
*
* Returns the hibernate write I/O function to use on this machine
*/
hibio_fn
-get_hibernate_io_function(void)
+get_hibernate_io_function(dev_t dev)
{
- char *blkname = findblkname(major(swdevt[0].sw_dev));
+ char *blkname = findblkname(major(dev));
if (blkname == NULL)
return NULL;
if (strcmp(blkname, "wd") == 0)
return wd_hibernate_io;
#endif
-#if NAHCI > 0 && NSD > 0
+#if NSD > 0
if (strcmp(blkname, "sd") == 0) {
extern struct cfdriver sd_cd;
extern int ahci_hibernate_io(dev_t dev, daddr_t blkno,
vaddr_t addr, size_t size, int op, void *page);
+ extern int sr_hibernate_io(dev_t dev, daddr_t blkno,
+ vaddr_t addr, size_t size, int op, void *page);
struct device *dv;
+#if NAHCI > 0
dv = disk_lookup(&sd_cd, DISKUNIT(swdevt[0].sw_dev));
if (dv && dv->dv_parent && dv->dv_parent->dv_parent &&
strcmp(dv->dv_parent->dv_parent->dv_cfdata->cf_driver->cd_name,
"ahci") == 0)
return ahci_hibernate_io;
+#endif
+#if NSOFTRAID > 0
+ if (dv && dv->dv_parent && dv->dv_parent->dv_parent &&
+ strcmp(dv->dv_parent->dv_parent->dv_cfdata->cf_driver->cd_name,
+ "softraid") == 0)
+ return sr_hibernate_io;
}
#endif
+#endif /* NSD > 0 */
return NULL;
}
-/* $OpenBSD: acpi.c,v 1.266 2014/07/16 07:42:50 mlarkin Exp $ */
+/* $OpenBSD: acpi.c,v 1.267 2014/07/20 18:05:21 mlarkin Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
* Copyright (c) 2005 Jordan Hargrave <jordan@openbsd.org>
error = EBADF;
break;
}
- if (get_hibernate_io_function() == NULL) {
+ if (get_hibernate_io_function(swdevt[0].sw_dev) == NULL) {
error = EOPNOTSUPP;
break;
}
-/* $OpenBSD: softraid.c,v 1.335 2014/07/13 23:10:23 deraadt Exp $ */
+/* $OpenBSD: softraid.c,v 1.336 2014/07/20 18:05:21 mlarkin Exp $ */
/*
* Copyright (c) 2007, 2008, 2009 Marco Peereboom <marco@peereboom.us>
* Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org>
#include <dev/softraidvar.h>
#include <dev/rndvar.h>
+#ifdef HIBERNATE
+#include <lib/libsa/aes_xts.h>
+#include <sys/hibernate.h>
+#include <scsi/sdvar.h>
+#endif /* HIBERNATE */
+
/* #define SR_FANCY_STATS */
#ifdef SR_DEBUG
}
#endif /* SR_DEBUG */
+
+#ifdef HIBERNATE
+/*
+ * Side-effect free (no malloc, printf, pool, splx) softraid crypto writer.
+ *
+ * This function must perform the following:
+ * 1. Determine the underlying device's own side-effect free I/O function
+ * (eg, ahci_hibernate_io, wd_hibernate_io, etc).
+ * 2. Store enough information in the provided page argument for subsequent
+ * I/O calls (such as the crypto discipline structure for the keys, the
+ * offset of the softraid partition on the underlying disk, as well as
+ * the offset of the swap partition within the crypto volume.
+ * 3. Encrypt the incoming data using the sr_discipline keys, then pass
+ * the request to the underlying device's own I/O function.
+ */
+int
+sr_hibernate_io(dev_t dev, daddr_t blkno, vaddr_t addr, size_t size, int op, void *page)
+{
+ /* Struct for stashing data obtained on HIB_INIT.
+ * XXX
+ * We share the page with the underlying device's own
+ * side-effect free I/O function, so we pad our data to
+ * the end of the page. Presently this does not overlap
+ * with either of the two other side-effect free i/o
+ * functions (ahci/wd).
+ */
+ struct {
+ char pad[3072];
+ struct sr_discipline *srd;
+ hibio_fn subfn; /* underlying device i/o fn */
+ dev_t subdev; /* underlying device dev_t */
+ daddr_t sr_swapoff; /* ofs of swap part in sr volume */
+ char buf[DEV_BSIZE]; /* encryption performed into this buf */
+ } *my = page;
+ extern struct cfdriver sd_cd;
+ char errstr[128], *dl_ret;
+ struct sr_chunk *schunk;
+ struct sd_softc *sd;
+ struct aes_xts_ctx ctx;
+ struct sr_softc *sc;
+ struct device *dv;
+ daddr_t key_blkno;
+ uint32_t sub_raidoff; /* ofs of sr part in underlying dev */
+ struct disklabel dl;
+ size_t i, j;
+ u_char iv[8];
+
+ /*
+ * In HIB_INIT, we are passed the swap partition size and offset
+ * in 'size' and 'blkno' respectively. These are relative to the
+ * start of the softraid partition, and we need to save these
+ * for later translation to the underlying device's layout.
+ */
+ if (op == HIB_INIT) {
+ dv = disk_lookup(&sd_cd, DISKUNIT(dev));
+ sd = (struct sd_softc *)dv;
+ sc = (struct sr_softc *)dv->dv_parent->dv_parent;
+
+ /*
+ * Look up the sr discipline. This is used to determine
+ * if we are SR crypto and what the underlying device is.
+ */
+ my->srd = sc->sc_targets[sd->sc_link->target];
+ DNPRINTF(SR_D_MISC, "sr_hibernate_io: discipline is %s\n",
+ my->srd->sd_name);
+ if (strncmp(my->srd->sd_name, "CRYPTO", 10))
+ return (ENOTSUP);
+
+ /* Find the underlying device */
+ schunk = my->srd->sd_vol.sv_chunks[0];
+ my->subdev = schunk->src_dev_mm;
+
+ /*
+ * Find the appropriate underlying device side effect free
+ * I/O function, based on the type of device it is.
+ */
+ my->subfn = get_hibernate_io_function(my->subdev);
+
+ /*
+ * Find block offset where this raid partition is on
+ * the underlying disk.
+ */
+ dl_ret = disk_readlabel(&dl, my->subdev, errstr,
+ sizeof(errstr));
+ if (dl_ret) {
+ printf("Hibernate error reading disklabel: %s\n", dl_ret);
+ return (ENOTSUP);
+ }
+
+ if (dl.d_partitions[DISKPART(my->subdev)].p_fstype != FS_RAID ||
+ DL_GETPSIZE(&dl.d_partitions[DISKPART(my->subdev)]) == 0)
+ return (ENOTSUP);
+
+ /* Find the offset of the SR part in the underlying device */
+ sub_raidoff = my->srd->sd_meta->ssd_data_offset +
+ DL_GETPOFFSET(&dl.d_partitions[DISKPART(my->subdev)]);
+ DNPRINTF(SR_D_MISC,"sr_hibernate_io: blk trans ofs: %d blks\n",
+ sub_raidoff);
+
+ /* Save the offset of the swap partition in the SR disk */
+ my->sr_swapoff = blkno;
+
+ /* Initialize the sub-device */
+ return my->subfn(my->subdev, sub_raidoff + blkno,
+ addr, size, op, page);
+ }
+
+ /* Hibernate only uses (and we only support) writes */
+ if (op != HIB_W)
+ return (ENOTSUP);
+
+ /*
+ * Blocks act as the IV for the encryption. These block numbers
+ * are relative to the start of the sr partition, but the 'blkno'
+ * passed above is relative to the start of the swap partition
+ * inside the sr partition, so bias appropriately.
+ */
+ key_blkno = my->sr_swapoff + blkno;
+
+ /* Process each disk block one at a time. */
+ for (i = 0; i < size; i += DEV_BSIZE) {
+ int res;
+
+ bzero(&ctx, sizeof(ctx));
+
+ /*
+ * Set encryption key (from the sr discipline stashed
+ * during HIB_INIT. This code is based on the softraid
+ * bootblock code.
+ */
+ aes_xts_setkey(&ctx, my->srd->mds.mdd_crypto.scr_key[0], 64);
+ /* We encrypt DEV_BSIZE bytes at a time in my->buf */
+ bcopy(((char *)addr) + i, my->buf, DEV_BSIZE);
+
+ /* Block number is the IV */
+ bcopy(&key_blkno, &iv, sizeof(key_blkno));
+ aes_xts_reinit(&ctx, iv);
+
+ /* Encrypt DEV_BSIZE bytes, AES_XTS_BLOCKSIZE bytes at a time */
+ for (j = 0; j < DEV_BSIZE; j += AES_XTS_BLOCKSIZE)
+ aes_xts_encrypt(&ctx, my->buf + j);
+
+ /*
+ * Write one block out from my->buf to the underlying device
+ * using its own side-effect free I/O function.
+ */
+ res = my->subfn(my->subdev, blkno + (i / DEV_BSIZE),
+ (vaddr_t)(my->buf), DEV_BSIZE, op, page);
+ if (res != 0)
+ return (res);
+ key_blkno++;
+ }
+
+ return (0);
+}
+#endif /* HIBERNATE */
-/* $OpenBSD: softraidvar.h,v 1.156 2014/07/12 07:39:11 blambert Exp $ */
+/* $OpenBSD: softraidvar.h,v 1.157 2014/07/20 18:05:21 mlarkin Exp $ */
/*
* Copyright (c) 2006 Marco Peereboom <marco@peereboom.us>
* Copyright (c) 2008 Chris Kuethe <ckuethe@openbsd.org>
struct sr_chunk * sr_crypto_create_key_disk(struct sr_discipline *, dev_t);
struct sr_chunk * sr_crypto_read_key_disk(struct sr_discipline *, dev_t);
+/* Hibernate I/O function */
+int sr_hibernate_io(dev_t dev, daddr_t blkno, vaddr_t addr,
+ size_t size, int op, void *page);
+
#ifdef SR_DEBUG
void sr_dump_block(void *, int);
void sr_dump_mem(u_int8_t *, int);
-/* $OpenBSD: subr_hibernate.c,v 1.97 2014/07/16 07:42:51 mlarkin Exp $ */
+/* $OpenBSD: subr_hibernate.c,v 1.98 2014/07/20 18:05:21 mlarkin Exp $ */
/*
* Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl>
#endif /* ! NO_PROPOLICE */
/* Determine I/O function to use */
- hib->io_func = get_hibernate_io_function();
+ hib->io_func = get_hibernate_io_function(swdevt[0].sw_dev);
if (hib->io_func == NULL)
return (1);
hib->dev = swdevt[0].sw_dev;
/* Read disklabel (used to calculate signature and image offsets) */
- dl_ret = disk_readlabel(&dl, hib->dev, err_string, 128);
+ dl_ret = disk_readlabel(&dl, hib->dev, err_string, sizeof(err_string));
if (dl_ret) {
printf("Hibernate error reading disklabel: %s\n", dl_ret);
-/* $OpenBSD: hibernate.h,v 1.35 2014/07/16 07:42:51 mlarkin Exp $ */
+/* $OpenBSD: hibernate.h,v 1.36 2014/07/20 18:05:21 mlarkin Exp $ */
/*
* Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl>
int uvm_page_rle(paddr_t);
void uvmpd_hibernate(void);
-hibio_fn get_hibernate_io_function(void);
+hibio_fn get_hibernate_io_function(dev_t);
int get_hibernate_info(union hibernate_info *, int);
int hibernate_zlib_reset(union hibernate_info *, int);