summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Larkin <mlarkin@cvs.openbsd.org>2013-01-17 00:11:25 +0000
committerMike Larkin <mlarkin@cvs.openbsd.org>2013-01-17 00:11:25 +0000
commit912630dde59eb16b8bc97de41a25ae972a11d836 (patch)
tree47d96fa4f6f1cf347f8e12f201cf3a4db00d0e66
parenta7faed5c97ad934b45b555743421407e4bff7e1e (diff)
fix an error in the amd64 asm unhibernate code and a slight adjustment to
the MI hibernate code to handle 64 bit archs
-rw-r--r--sys/arch/amd64/amd64/acpi_wakecode.S5
-rw-r--r--sys/kern/subr_hibernate.c101
2 files changed, 65 insertions, 41 deletions
diff --git a/sys/arch/amd64/amd64/acpi_wakecode.S b/sys/arch/amd64/amd64/acpi_wakecode.S
index 5c29d590e22..3c1fe70a58b 100644
--- a/sys/arch/amd64/amd64/acpi_wakecode.S
+++ b/sys/arch/amd64/amd64/acpi_wakecode.S
@@ -1,4 +1,4 @@
-/* $OpenBSD: acpi_wakecode.S,v 1.14 2013/01/16 22:45:40 mlarkin Exp $ */
+/* $OpenBSD: acpi_wakecode.S,v 1.15 2013/01/17 00:11:24 mlarkin Exp $ */
/*
* Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org>
* Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org>
@@ -391,13 +391,12 @@ NENTRY(hibernate_resume_machdep)
jmp *%rax
_ACPI_TRMP_LABEL(hibernate_resume_vector_2)
- .code32
/* Get out of 64 bit CS */
lgdtq tmp_gdt6416
rex64 ljmp *(hibernate_indirect_16)
_ACPI_TRMP_LABEL(hibernate_indirect_16)
- .quad hibernate_resume_vector3
+ .quad hibernate_resume_vector_3
.word 0x18
_ACPI_TRMP_LABEL(hibernate_resume_vector_3)
diff --git a/sys/kern/subr_hibernate.c b/sys/kern/subr_hibernate.c
index 0bb12943452..d4802ad0bb8 100644
--- a/sys/kern/subr_hibernate.c
+++ b/sys/kern/subr_hibernate.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: subr_hibernate.c,v 1.46 2012/07/19 18:07:03 deraadt Exp $ */
+/* $OpenBSD: subr_hibernate.c,v 1.47 2013/01/17 00:11:24 mlarkin Exp $ */
/*
* Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl>
@@ -42,6 +42,8 @@ union hibernate_info disk_hiber_info;
paddr_t global_pig_start;
vaddr_t global_piglet_va;
+void hibernate_copy_chunk_to_piglet(paddr_t, vaddr_t, size_t);
+
/*
* Hib alloc enforced alignment.
*/
@@ -1161,7 +1163,7 @@ hibernate_unpack_image(union hibernate_info *hiber_info)
struct hibernate_disk_chunk *chunks;
union hibernate_info local_hiber_info;
paddr_t image_cur = global_pig_start;
- int *fchunks, i;
+ int i, *fchunks;
char *pva = (char *)hiber_info->piglet_va;
struct hibernate_zlib_state *hibernate_state;
@@ -1169,7 +1171,7 @@ hibernate_unpack_image(union hibernate_info *hiber_info)
/* Mask off based on arch-specific piglet page size */
pva = (char *)((paddr_t)pva & (PIGLET_PAGE_MASK));
- fchunks = (int *)(pva + (6 * PAGE_SIZE));
+ fchunks = (int *)(pva + (4 * PAGE_SIZE));
chunks = (struct hibernate_disk_chunk *)(pva + HIBERNATE_CHUNK_SIZE);
@@ -1192,7 +1194,43 @@ hibernate_unpack_image(union hibernate_info *hiber_info)
}
/*
- * Process a chunk by ensuring its proper placement, followed by unpacking
+ * Bounce a compressed image chunk to the piglet, entering mappings for the
+ * copied pages as needed
+ */
+void
+hibernate_copy_chunk_to_piglet(paddr_t img_cur, vaddr_t piglet, size_t size)
+{
+ size_t ct, ofs;
+ paddr_t src = img_cur;
+ vaddr_t dest = piglet;
+
+ /* Copy first partial page */
+ ct = (PAGE_SIZE) - (src & PAGE_MASK);
+ ofs = (src & PAGE_MASK);
+
+ if (ct < PAGE_SIZE) {
+ hibernate_enter_resume_mapping(HIBERNATE_INFLATE_PAGE,
+ (src - ofs), 0);
+ hibernate_flush();
+ bcopy((caddr_t)(HIBERNATE_INFLATE_PAGE + ofs), (caddr_t)dest, ct);
+ src += ct;
+ dest += ct;
+ }
+
+ /* Copy remaining pages */
+ while (src < size + img_cur) {
+ hibernate_enter_resume_mapping(HIBERNATE_INFLATE_PAGE, src, 0);
+ hibernate_flush();
+ ct = PAGE_SIZE;
+ bcopy((caddr_t)(HIBERNATE_INFLATE_PAGE), (caddr_t)dest, ct);
+ hibernate_flush();
+ src += ct;
+ dest += ct;
+ }
+}
+
+/*
+ * Process a chunk by bouncing it to the piglet, followed by unpacking
*/
void
hibernate_process_chunk(union hibernate_info *hiber_info,
@@ -1200,21 +1238,12 @@ hibernate_process_chunk(union hibernate_info *hiber_info,
{
char *pva = (char *)hiber_info->piglet_va;
- /*
- * If there is a conflict, copy the chunk to the piglet area
- * before unpacking it to its original location.
- */
- if ((chunk->flags & HIBERNATE_CHUNK_CONFLICT) == 0)
- hibernate_inflate_region(hiber_info, chunk->base,
- img_cur, chunk->compressed_size);
- else {
- bcopy((caddr_t)img_cur,
- pva + (HIBERNATE_CHUNK_SIZE * 2),
- chunk->compressed_size);
- hibernate_inflate_region(hiber_info, chunk->base,
- (vaddr_t)(pva + (HIBERNATE_CHUNK_SIZE * 2)),
- chunk->compressed_size);
- }
+ hibernate_copy_chunk_to_piglet(img_cur,
+ (vaddr_t)(pva + (HIBERNATE_CHUNK_SIZE * 2)), chunk->compressed_size);
+
+ hibernate_inflate_region(hiber_info, chunk->base,
+ (vaddr_t)(pva + (HIBERNATE_CHUNK_SIZE * 2)),
+ chunk->compressed_size);
}
/*
@@ -1254,7 +1283,7 @@ hibernate_write_chunks(union hibernate_info *hiber_info)
/*
* Allocate VA for the temp and copy page.
- * These will becomee part of the suspended kernel and will
+ * These will become part of the suspended kernel and will
* be freed in hibernate_free, upon resume.
*/
hibernate_temp_page = (vaddr_t)km_alloc(PAGE_SIZE, &kv_any,
@@ -1420,7 +1449,7 @@ hibernate_zlib_reset(union hibernate_info *hiber_info, int deflate)
if(!deflate)
pva = (char *)((paddr_t)pva & (PIGLET_PAGE_MASK));
- hibernate_zlib_start = (vaddr_t)(pva + (8 * PAGE_SIZE));
+ hibernate_zlib_start = (vaddr_t)(pva + (28 * PAGE_SIZE));
hibernate_zlib_size = 80 * PAGE_SIZE;
bzero((caddr_t)hibernate_zlib_start, hibernate_zlib_size);
@@ -1540,9 +1569,9 @@ hibernate_read_chunks(union hibernate_info *hib_info, paddr_t pig_start,
paddr_t piglet_end = piglet_base + HIBERNATE_CHUNK_SIZE;
daddr_t blkctr;
size_t processed, compressed_size, read_size;
- int i, j, overlap, found, nchunks;
- int nochunks = 0, nfchunks = 0, npchunks = 0;
+ int overlap, found, nchunks, nochunks = 0, nfchunks = 0, npchunks = 0;
int *ochunks, *pchunks, *fchunks;
+ int i, j;
vaddr_t tempva = (vaddr_t)NULL, hibernate_fchunk_area = (vaddr_t)NULL;
global_pig_start = pig_start;
@@ -1558,30 +1587,26 @@ hibernate_read_chunks(union hibernate_info *hib_info, paddr_t pig_start,
tempva = (vaddr_t)km_alloc(2*PAGE_SIZE, &kv_any, &kp_none, &kd_nowait);
if (!tempva)
return (1);
- hibernate_fchunk_area = (vaddr_t)km_alloc(3*PAGE_SIZE, &kv_any,
+ hibernate_fchunk_area = (vaddr_t)km_alloc(24*PAGE_SIZE, &kv_any,
&kp_none, &kd_nowait);
if (!hibernate_fchunk_area)
return (1);
- /* Temporary output chunk ordering VA */
- ochunks = (int *)hibernate_fchunk_area;
+ /* Final output chunk ordering VA */
+ fchunks = (int *)hibernate_fchunk_area;
/* Piglet chunk ordering VA */
- pchunks = (int *)(hibernate_fchunk_area + PAGE_SIZE);
+ pchunks = (int *)(hibernate_fchunk_area + (PAGE_SIZE));
/* Final chunk ordering VA */
- fchunks = (int *)(hibernate_fchunk_area + (2*PAGE_SIZE));
+ ochunks = (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());
+ for(i=0; i<3 ; i++) {
+ pmap_kenter_pa(hibernate_fchunk_area + (i*PAGE_SIZE),
+ piglet_base + ((4+i)*PAGE_SIZE), VM_PROT_ALL);
+ pmap_update(pmap_kernel());
+ }
nchunks = hib_info->chunk_ctr;
@@ -1620,7 +1645,7 @@ hibernate_read_chunks(union hibernate_info *hib_info, paddr_t pig_start,
if (j != -1) {
found = 1;
- ochunks[nochunks] = (short)j;
+ ochunks[nochunks] = j;
nochunks++;
chunks[j].flags |= HIBERNATE_CHUNK_PLACED;
}