summaryrefslogtreecommitdiffstats
path: root/sys/kern/subr_hibernate.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern/subr_hibernate.c')
-rw-r--r--sys/kern/subr_hibernate.c125
1 files changed, 79 insertions, 46 deletions
diff --git a/sys/kern/subr_hibernate.c b/sys/kern/subr_hibernate.c
index 63e3dbd9d87..eb4f5cb970e 100644
--- a/sys/kern/subr_hibernate.c
+++ b/sys/kern/subr_hibernate.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr_hibernate.c,v 1.34 2012/04/12 14:57:36 ariane Exp $ */
+/* $OpenBSD: subr_hibernate.c,v 1.35 2012/06/20 17:31:55 mlarkin Exp $ */
/*
* Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl>
@@ -32,8 +32,6 @@
#include <uvm/uvm.h>
#include <machine/hibernate.h>
-struct hibernate_zlib_state *hibernate_state;
-
/* Temporary vaddr ranges used during hibernate */
vaddr_t hibernate_temp_page;
vaddr_t hibernate_copy_page;
@@ -697,6 +695,10 @@ fail:
void
*hibernate_zlib_alloc(void *unused, int nitems, int size)
{
+ struct hibernate_zlib_state *hibernate_state;
+
+ hibernate_state = (struct hibernate_zlib_state *)HIBERNATE_HIBALLOC_PAGE;
+
return hib_alloc(&hibernate_state->hiballoc_arena, nitems*size);
}
@@ -707,6 +709,10 @@ void
void
hibernate_zlib_free(void *unused, void *addr)
{
+ struct hibernate_zlib_state *hibernate_state;
+
+ hibernate_state = (struct hibernate_zlib_state *)HIBERNATE_HIBALLOC_PAGE;
+
hib_free(&hibernate_state->hiballoc_arena, addr);
}
@@ -723,6 +729,9 @@ hibernate_inflate(union hibernate_info *hiber_info, paddr_t dest,
paddr_t src, size_t size)
{
int i, rle;
+ struct hibernate_zlib_state *hibernate_state;
+
+ hibernate_state = (struct hibernate_zlib_state *)HIBERNATE_HIBALLOC_PAGE;
hibernate_state->hib_stream.next_in = (char *)src;
hibernate_state->hib_stream.avail_in = size;
@@ -731,54 +740,43 @@ hibernate_inflate(union hibernate_info *hiber_info, paddr_t dest,
/* Flush cache and TLB */
hibernate_flush();
- /* Read RLE code */
- hibernate_state->hib_stream.next_out = (char *)&rle;
- hibernate_state->hib_stream.avail_out = sizeof(rle);
-
- i = inflate(&hibernate_state->hib_stream, Z_FULL_FLUSH);
- if (i != Z_OK && i != Z_STREAM_END) {
- /*
- * XXX - this will likely reboot/hang most machines,
- * but there's not much else we can do here.
- */
- panic("inflate rle error");
- }
-
- if (i == Z_STREAM_END)
- goto next_page;
-
- /* Skip while RLE code is != 0 */
- while (rle != 0) {
- dest += (rle * PAGE_SIZE);
+ do {
+ /* Read RLE code */
hibernate_state->hib_stream.next_out = (char *)&rle;
hibernate_state->hib_stream.avail_out = sizeof(rle);
- i = inflate(&hibernate_state->hib_stream,
- Z_FULL_FLUSH);
+ i = inflate(&hibernate_state->hib_stream, Z_FULL_FLUSH);
if (i != Z_OK && i != Z_STREAM_END) {
/*
- * XXX - this will likely reboot/hang most
- * machines but there's not much else
- * we can do here.
+ * XXX - this will likely reboot/hang most machines,
+ * but there's not much else we can do here.
*/
- panic("inflate rle error 2");
+ panic("inflate rle error");
}
- }
- if (i == Z_STREAM_END)
- goto next_page;
+ /* Sanity check what RLE value we got */
+ if (rle > HIBERNATE_CHUNK_SIZE/PAGE_SIZE || rle < 0)
+ panic("inflate rle error 3");
+
+ if (rle != 0)
+ dest += (rle * PAGE_SIZE);
+ if (i == Z_STREAM_END)
+ goto next_page;
+
+ } while (rle != 0);
/*
* Is this a special page? If yes, redirect the
* inflate output to a scratch page (eg, discard it)
*/
- if (hibernate_inflate_skip(hiber_info, dest))
+ if (hibernate_inflate_skip(hiber_info, dest)) {
hibernate_enter_resume_mapping(
HIBERNATE_INFLATE_PAGE,
HIBERNATE_INFLATE_PAGE, 0);
- else
+ } else {
hibernate_enter_resume_mapping(
HIBERNATE_INFLATE_PAGE, dest, 0);
+ }
hibernate_flush();
@@ -794,7 +792,8 @@ hibernate_inflate(union hibernate_info *hiber_info, paddr_t dest,
* XXX - this will likely reboot/hang most machines,
* but there's not much else we can do here.
*/
- panic("inflate error");
+
+ panic("inflate error");
}
next_page:
@@ -814,6 +813,9 @@ hibernate_deflate(union hibernate_info *hiber_info, paddr_t src,
size_t *remaining)
{
vaddr_t hibernate_io_page = hiber_info->piglet_va + PAGE_SIZE;
+ struct hibernate_zlib_state *hibernate_state;
+
+ hibernate_state = (struct hibernate_zlib_state *)HIBERNATE_HIBALLOC_PAGE;
/* Set up the stream for deflate */
hibernate_state->hib_stream.next_in = (caddr_t)src;
@@ -1061,6 +1063,8 @@ hibernate_resume(void)
if (hibernate_compare_signature(&hiber_info, &disk_hiber_info))
return;
+ uvm_pmr_zero_everything();
+
/* Read the image from disk into the image (pig) area */
if (hibernate_read_image(&disk_hiber_info))
goto fail;
@@ -1070,6 +1074,9 @@ hibernate_resume(void)
disable_intr();
cold = 1;
+ pmap_kenter_pa(HIBERNATE_HIBALLOC_PAGE, HIBERNATE_HIBALLOC_PAGE, VM_PROT_ALL);
+ pmap_activate(curproc);
+
/* Switch stacks */
hibernate_switch_stack_machdep();
@@ -1108,6 +1115,9 @@ hibernate_unpack_image(union hibernate_info *hiber_info)
paddr_t image_cur = global_pig_start;
int *fchunks, i;
char *pva = (char *)hiber_info->piglet_va;
+ struct hibernate_zlib_state *hibernate_state;
+
+ hibernate_state = (struct hibernate_zlib_state *)HIBERNATE_HIBALLOC_PAGE;
/* Mask off based on arch-specific piglet page size */
pva = (char *)((paddr_t)pva & (PIGLET_PAGE_MASK));
@@ -1118,9 +1128,6 @@ hibernate_unpack_image(union hibernate_info *hiber_info)
/* Can't use hiber_info that's passed in after here */
bcopy(hiber_info, &local_hiber_info, sizeof(union hibernate_info));
- hibernate_state = (struct hibernate_zlib_state *)
- (pva + (7 * PAGE_SIZE));
-
hibernate_activate_resume_pt_machdep();
for (i = 0; i < local_hiber_info.chunk_ctr; i++) {
@@ -1194,6 +1201,9 @@ hibernate_write_chunks(union hibernate_info *hiber_info)
vaddr_t hibernate_io_page = hiber_info->piglet_va + PAGE_SIZE;
daddr_t blkctr = hiber_info->image_offset, offset = 0;
int i, rle;
+ struct hibernate_zlib_state *hibernate_state;
+
+ hibernate_state = (struct hibernate_zlib_state *)HIBERNATE_HIBALLOC_PAGE;
hiber_info->chunk_ctr = 0;
@@ -1270,8 +1280,12 @@ hibernate_write_chunks(union hibernate_info *hiber_info)
*/
temp_inaddr = (inaddr & PAGE_MASK) +
hibernate_copy_page;
+
+ if (hibernate_inflate_skip(hiber_info, inaddr))
+ rle = 1;
+ else
+ rle = uvm_page_rle(inaddr);
- rle = uvm_page_rle(inaddr);
while (rle != 0 && inaddr < range_end) {
hibernate_state->hib_stream.next_in =
(char *)&rle;
@@ -1429,9 +1443,12 @@ hibernate_zlib_reset(union hibernate_info *hiber_info, int deflate)
vaddr_t hibernate_zlib_start;
size_t hibernate_zlib_size;
char *pva = (char *)hiber_info->piglet_va;
+ struct hibernate_zlib_state *hibernate_state;
- hibernate_state = (struct hibernate_zlib_state *)
- (pva + (7 * PAGE_SIZE));
+ hibernate_state = (struct hibernate_zlib_state *)HIBERNATE_HIBALLOC_PAGE;
+
+ if(!deflate)
+ pva = (char *)((paddr_t)pva & (PIGLET_PAGE_MASK));
hibernate_zlib_start = (vaddr_t)(pva + (8 * PAGE_SIZE));
hibernate_zlib_size = 80 * PAGE_SIZE;
@@ -1477,6 +1494,8 @@ hibernate_read_image(union hibernate_info *hiber_info)
HIBERNATE_CHUNK_SIZE;
int i;
+ pmap_activate(curproc);
+
/* Calculate total chunk table size in disk blocks */
chunktable_size = HIBERNATE_CHUNK_TABLE_SIZE / hiber_info->secsize;
@@ -1493,13 +1512,14 @@ hibernate_read_image(union hibernate_info *hiber_info)
for (i = 0; i < HIBERNATE_CHUNK_TABLE_SIZE;
i += PAGE_SIZE, blkctr += PAGE_SIZE/hiber_info->secsize) {
pmap_kenter_pa(chunktable + i, piglet_chunktable + i, VM_PROT_ALL);
+ pmap_update(pmap_kernel());
hibernate_read_block(hiber_info, blkctr, PAGE_SIZE,
chunktable + i);
}
blkctr = hiber_info->image_offset;
compressed_size = 0;
- pmap_kenter_pa(chunktable, piglet_chunktable, VM_PROT_ALL);
+
chunks = (struct hibernate_disk_chunk *)chunktable;
for (i = 0; i < hiber_info->chunk_ctr; i++)
@@ -1523,6 +1543,9 @@ hibernate_read_image(union hibernate_info *hiber_info)
hibernate_read_chunks(hiber_info, image_start, image_end, disk_size,
chunks);
+ pmap_kremove(chunktable, PAGE_SIZE);
+ pmap_update(pmap_kernel());
+
/* Prepare the resume time pmap/page table */
hibernate_populate_resume_pt(hiber_info, image_start, image_end);
@@ -1584,22 +1607,25 @@ hibernate_read_chunks(union hibernate_info *hib_info, paddr_t pig_start,
if (!hibernate_fchunk_area)
return (1);
- /* Temporary output chunk ordering */
+ /* Temporary output chunk ordering VA */
ochunks = (int *)hibernate_fchunk_area;
- /* Piglet chunk ordering */
+ /* Piglet chunk ordering VA */
pchunks = (int *)(hibernate_fchunk_area + PAGE_SIZE);
- /* Final chunk ordering */
+ /* Final chunk ordering VA */
fchunks = (int *)(hibernate_fchunk_area + (2*PAGE_SIZE));
/* Map the chunk ordering region */
pmap_kenter_pa(hibernate_fchunk_area,
piglet_base + (4*PAGE_SIZE), VM_PROT_ALL);
+ pmap_update(pmap_kernel());
pmap_kenter_pa((vaddr_t)pchunks, piglet_base + (5*PAGE_SIZE),
VM_PROT_ALL);
+ pmap_update(pmap_kernel());
pmap_kenter_pa((vaddr_t)fchunks, piglet_base + (6*PAGE_SIZE),
VM_PROT_ALL);
+ pmap_update(pmap_kernel());
nchunks = hib_info->chunk_ctr;
@@ -1728,9 +1754,8 @@ hibernate_read_chunks(union hibernate_info *hib_info, paddr_t pig_start,
pmap_kenter_pa(tempva, img_cur, VM_PROT_ALL);
pmap_kenter_pa(tempva + PAGE_SIZE, img_cur+PAGE_SIZE,
VM_PROT_ALL);
+ pmap_update(pmap_kernel());
- /* XXX - not needed on all archs */
- pmap_activate(curproc);
if (compressed_size - processed >= PAGE_SIZE)
read_size = PAGE_SIZE;
else
@@ -1749,6 +1774,11 @@ hibernate_read_chunks(union hibernate_info *hib_info, paddr_t pig_start,
}
}
+ pmap_kremove(hibernate_fchunk_area, PAGE_SIZE);
+ pmap_kremove((vaddr_t)pchunks, PAGE_SIZE);
+ pmap_kremove((vaddr_t)fchunks, PAGE_SIZE);
+ pmap_update(pmap_kernel());
+
return (0);
}
@@ -1777,6 +1807,9 @@ hibernate_suspend(void)
if (get_hibernate_info(&hib_info, 1))
return (1);
+ pmap_kenter_pa(HIBERNATE_HIBALLOC_PAGE, HIBERNATE_HIBALLOC_PAGE, VM_PROT_ALL);
+ pmap_activate(curproc);
+
global_piglet_va = hib_info.piglet_va;
if (hibernate_write_chunks(&hib_info))