summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMike Larkin <mlarkin@cvs.openbsd.org>2012-03-26 16:15:43 +0000
committerMike Larkin <mlarkin@cvs.openbsd.org>2012-03-26 16:15:43 +0000
commit4ac206d01035fca15c436fdc6ace3f9ba322ddc0 (patch)
treeef3186fb4214eea54d3a3786af50b3560d1c8aac /sys
parente5b18d68d720b5e8167a56973fde63224f035621 (diff)
Fix an integer math error when using the result of uvm_page_rle, and
at the same time increase said function's max RLE page count return value. Add hooks in the right places to call the hibernate suspend and resume routines, so that we can enable hibernation with a HIBERNATE option line in GENERIC and appropriate acpi.c goo. discussed on and off with deraadt@ over the past few months
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/i386/i386/acpi_machdep.c14
-rw-r--r--sys/arch/i386/i386/autoconf.c7
-rw-r--r--sys/kern/subr_hibernate.c25
-rw-r--r--sys/sys/hibernate.h4
4 files changed, 33 insertions, 17 deletions
diff --git a/sys/arch/i386/i386/acpi_machdep.c b/sys/arch/i386/i386/acpi_machdep.c
index 95c753e3bda..027658fe2fe 100644
--- a/sys/arch/i386/i386/acpi_machdep.c
+++ b/sys/arch/i386/i386/acpi_machdep.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi_machdep.c,v 1.41 2010/10/06 18:21:09 kettenis Exp $ */
+/* $OpenBSD: acpi_machdep.c,v 1.42 2012/03/26 16:15:42 mlarkin Exp $ */
/*
* Copyright (c) 2005 Thorsten Lockert <tholo@sigmasoft.com>
*
@@ -23,6 +23,7 @@
#include <sys/memrange.h>
#include <sys/proc.h>
#include <sys/user.h>
+#include <sys/hibernate.h>
#include <uvm/uvm_extern.h>
@@ -263,12 +264,23 @@ acpi_sleep_machdep(struct acpi_softc *sc, int state)
i386_broadcast_ipi(I386_IPI_HALT);
#endif
wbinvd();
+#ifdef HIBERNATE
+ if (state == ACPI_STATE_S4)
+ if (hibernate_suspend())
+ panic("%s: hibernate failed", DEVNAME(sc));
+#endif
acpi_enter_sleep_state(sc, state);
panic("%s: acpi_enter_sleep_state failed", DEVNAME(sc));
}
/* Resume path continues here */
+#ifdef HIBERNATE
+ /* Free piglet and other pages allocated during suspend */
+ if (state == ACPI_STATE_S4)
+ hibernate_free();
+#endif
+
/* Reset the vector */
sc->sc_facs->wakeup_vector = 0;
diff --git a/sys/arch/i386/i386/autoconf.c b/sys/arch/i386/i386/autoconf.c
index fa34ca1acd1..3ff07dd2cf4 100644
--- a/sys/arch/i386/i386/autoconf.c
+++ b/sys/arch/i386/i386/autoconf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: autoconf.c,v 1.88 2011/06/26 23:19:11 tedu Exp $ */
+/* $OpenBSD: autoconf.c,v 1.89 2012/03/26 16:15:42 mlarkin Exp $ */
/* $NetBSD: autoconf.c,v 1.20 1996/05/03 19:41:56 christos Exp $ */
/*-
@@ -67,6 +67,7 @@
#include <machine/gdt.h>
#include <machine/biosvar.h>
#include <machine/kvm86.h>
+#include <sys/hibernate.h>
#include <dev/cons.h>
@@ -208,6 +209,10 @@ diskconf(void)
setroot(bootdv, part, RB_USERREQ);
dumpconf();
+
+#ifdef HIBERNATE
+ hibernate_resume();
+#endif /* HIBERNATE */
}
struct nam2blk nam2blk[] = {
diff --git a/sys/kern/subr_hibernate.c b/sys/kern/subr_hibernate.c
index 4c3c9c7d06a..45ed48f1867 100644
--- a/sys/kern/subr_hibernate.c
+++ b/sys/kern/subr_hibernate.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr_hibernate.c,v 1.32 2011/11/29 05:21:08 deraadt Exp $ */
+/* $OpenBSD: subr_hibernate.c,v 1.33 2012/03/26 16:15:42 mlarkin Exp $ */
/*
* Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl>
@@ -565,10 +565,10 @@ uvm_pmr_free_piglet(vaddr_t va, vsize_t sz)
* Physmem RLE compression support.
*
* Given a physical page address, it will return the number of pages
- * starting at the address, that are free. Clamps to a max of 255 pages.
- * Returns 0 if the page at addr is not free.
+ * starting at the address, that are free. Clamps to the number of pages in
+ * HIBERNATE_CHUNK_SIZE. Returns 0 if the page at addr is not free.
*/
-u_char
+int
uvm_page_rle(paddr_t addr)
{
struct vm_page *pg, *pg_end;
@@ -592,7 +592,7 @@ uvm_page_rle(paddr_t addr)
for (pg_end = pg; pg_end <= vmp->lastpg &&
(pg_end->pg_flags & PQ_FREE) == PQ_FREE; pg_end++)
;
- return max(pg_end - pg, 255);
+ return min((pg_end - pg), HIBERNATE_CHUNK_SIZE/PAGE_SIZE);
}
/*
@@ -722,8 +722,7 @@ void
hibernate_inflate(union hibernate_info *hiber_info, paddr_t dest,
paddr_t src, size_t size)
{
- int i;
- u_char rle;
+ int i, rle;
hibernate_state->hib_stream.next_in = (char *)src;
hibernate_state->hib_stream.avail_in = size;
@@ -1190,11 +1189,11 @@ int
hibernate_write_chunks(union hibernate_info *hiber_info)
{
paddr_t range_base, range_end, inaddr, temp_inaddr;
- size_t nblocks, out_remaining, used, offset = 0;
+ size_t nblocks, out_remaining, used;
struct hibernate_disk_chunk *chunks;
vaddr_t hibernate_io_page = hiber_info->piglet_va + PAGE_SIZE;
- daddr_t blkctr = hiber_info->image_offset;
- int i;
+ daddr_t blkctr = hiber_info->image_offset, offset = 0;
+ int i, rle;
hiber_info->chunk_ctr = 0;
@@ -1263,7 +1262,6 @@ hibernate_write_chunks(union hibernate_info *hiber_info)
while (inaddr < range_end) {
out_remaining = PAGE_SIZE;
while (out_remaining > 0 && inaddr < range_end) {
- u_char rle;
/*
* Adjust for regions that are not evenly
@@ -1615,8 +1613,8 @@ hibernate_read_chunks(union hibernate_info *hib_info, paddr_t pig_start,
*/
for (i = 0; i < nchunks; i++) {
if (chunks[i].end <= pig_start || chunks[i].base >= pig_end) {
- ochunks[nochunks] = (u_int8_t)i;
- fchunks[nfchunks] = (u_int8_t)i;
+ ochunks[nochunks] = i;
+ fchunks[nfchunks] = i;
nochunks++;
nfchunks++;
chunks[i].flags |= HIBERNATE_CHUNK_USED;
@@ -1681,6 +1679,7 @@ hibernate_read_chunks(union hibernate_info *hib_info, paddr_t pig_start,
piglet_cur = piglet_base;
npchunks = 0;
j = i;
+
while (copy_start < copy_end && j < nochunks) {
piglet_cur += chunks[ochunks[j]].compressed_size;
pchunks[npchunks] = ochunks[j];
diff --git a/sys/sys/hibernate.h b/sys/sys/hibernate.h
index aa96f38d33a..17a56d65e0f 100644
--- a/sys/sys/hibernate.h
+++ b/sys/sys/hibernate.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: hibernate.h,v 1.19 2011/11/29 05:21:10 deraadt Exp $ */
+/* $OpenBSD: hibernate.h,v 1.20 2012/03/26 16:15:42 mlarkin Exp $ */
/*
* Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl>
@@ -105,7 +105,7 @@ void uvm_pmr_dirty_everything(void);
int uvm_pmr_alloc_pig(paddr_t*, psize_t);
int uvm_pmr_alloc_piglet(vaddr_t*, paddr_t*, vsize_t, paddr_t);
void uvm_pmr_free_piglet(vaddr_t, vsize_t);
-u_char uvm_page_rle(paddr_t);
+int uvm_page_rle(paddr_t);
hibio_fn get_hibernate_io_function(void);
int get_hibernate_info(union hibernate_info *, int);