From: mlarkin Date: Wed, 16 Jul 2014 07:42:50 +0000 (+0000) Subject: Reenable hibernate RLE support and flush+zero all memory after unpack. X-Git-Url: http://artulab.com/gitweb/?a=commitdiff_plain;h=7882bc75851a5e1207ca424d66b9f466cbf36715;p=openbsd Reenable hibernate RLE support and flush+zero all memory after unpack. --- diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c index 215dc23ab4f..df188e3a2bc 100644 --- a/sys/arch/amd64/amd64/acpi_machdep.c +++ b/sys/arch/amd64/amd64/acpi_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi_machdep.c,v 1.61 2014/06/08 17:53:14 daniel Exp $ */ +/* $OpenBSD: acpi_machdep.c,v 1.62 2014/07/16 07:42:50 mlarkin Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert * @@ -303,12 +303,10 @@ acpi_sleep_cpu(struct acpi_softc *sc, int state) #ifdef HIBERNATE if (state == ACPI_STATE_S4) { - uvm_pmr_zero_everything(); if (hibernate_suspend()) { printf("%s: hibernate_suspend failed", DEVNAME(sc)); hibernate_free(); - uvm_pmr_dirty_everything(); return (ECANCELED); } } diff --git a/sys/arch/i386/i386/acpi_machdep.c b/sys/arch/i386/i386/acpi_machdep.c index af9c13facfd..397daeea4a5 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.54 2014/06/08 17:53:14 daniel Exp $ */ +/* $OpenBSD: acpi_machdep.c,v 1.55 2014/07/16 07:42:50 mlarkin Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert * @@ -326,12 +326,10 @@ acpi_sleep_cpu(struct acpi_softc *sc, int state) #ifdef HIBERNATE if (state == ACPI_STATE_S4) { - uvm_pmr_zero_everything(); if (hibernate_suspend()) { printf("%s: hibernate_suspend failed", DEVNAME(sc)); hibernate_free(); - uvm_pmr_dirty_everything(); return (ECANCELED); } } diff --git a/sys/dev/acpi/acpi.c b/sys/dev/acpi/acpi.c index c5c920fefbc..032f24d4ecc 100644 --- a/sys/dev/acpi/acpi.c +++ b/sys/dev/acpi/acpi.c @@ -1,4 +1,4 @@ -/* $OpenBSD: acpi.c,v 1.265 2014/07/12 18:48:17 tedu Exp $ */ +/* $OpenBSD: acpi.c,v 1.266 2014/07/16 07:42:50 mlarkin Exp $ */ /* * Copyright (c) 2005 Thorsten Lockert * Copyright (c) 2005 Jordan Hargrave @@ -2162,6 +2162,13 @@ acpi_sleep_state(struct acpi_softc *sc, int state) sc->sc_state = ACPI_STATE_S0; /* Resume */ +#ifdef HIBERNATE + if (state == ACPI_STATE_S4) { + uvm_pmr_dirty_everything(); + uvm_pmr_zero_everything(); + } +#endif /* HIBERNATE */ + acpi_resume_clocks(sc); /* AML may need clocks */ acpi_resume_pm(sc, state); acpi_resume_cpu(sc); @@ -2199,7 +2206,6 @@ fail_quiesce: #ifdef HIBERNATE if (state == ACPI_STATE_S4) { hibernate_free(); - uvm_pmr_dirty_everything(); hibernate_resume_bufcache(); } #endif /* HIBERNATE */ diff --git a/sys/kern/subr_hibernate.c b/sys/kern/subr_hibernate.c index ff825b60880..6f54d7e3470 100644 --- a/sys/kern/subr_hibernate.c +++ b/sys/kern/subr_hibernate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_hibernate.c,v 1.96 2014/07/09 15:12:34 mlarkin Exp $ */ +/* $OpenBSD: subr_hibernate.c,v 1.97 2014/07/16 07:42:51 mlarkin Exp $ */ /* * Copyright (c) 2011 Ariane van der Steldt @@ -50,8 +50,9 @@ * 4*PAGE_SIZE final chunk ordering list (8 pages) * 12*PAGE_SIZE piglet chunk ordering list (8 pages) * 20*PAGE_SIZE temp chunk ordering list (8 pages) - * 28*PAGE_SIZE start of hiballoc area - * 108*PAGE_SIZE end of hiballoc area (80 pages) + * 28*PAGE_SIZE RLE utility page + * 29*PAGE_SIZE start of hiballoc area + * 109*PAGE_SIZE end of hiballoc area (80 pages) * ... unused * HIBERNATE_CHUNK_SIZE start of hibernate chunk table * 2*HIBERNATE_CHUNK_SIZE bounce area for chunks being unpacked @@ -61,6 +62,7 @@ /* Temporary vaddr ranges used during hibernate */ vaddr_t hibernate_temp_page; vaddr_t hibernate_copy_page; +vaddr_t hibernate_rle_page; /* Hibernate info as read from disk during resume */ union hibernate_info disk_hib; @@ -82,6 +84,11 @@ extern long __guard_local; #endif /* ! NO_PROPOLICE */ void hibernate_copy_chunk_to_piglet(paddr_t, vaddr_t, size_t); +int hibernate_calc_rle(paddr_t, paddr_t); +int hibernate_write_rle(union hibernate_info *, paddr_t, paddr_t, daddr_t *, + size_t *); + +#define MAX_RLE (HIBERNATE_CHUNK_SIZE / PAGE_SIZE) /* * Hib alloc enforced alignment. @@ -796,10 +803,15 @@ hibernate_zlib_free(void *unused, void *addr) } /* - * Inflate next page of data from the image stream + * Inflate next page of data from the image stream. + * The rle parameter is modified on exit to contain the number of pages to + * skip in the output stream (or 0 if this page was inflated into). + * + * Returns 0 if the stream contains additional data, or 1 if the stream is + * finished. */ int -hibernate_inflate_page(void) +hibernate_inflate_page(int *rle) { struct hibernate_zlib_state *hibernate_state; int i; @@ -807,7 +819,46 @@ hibernate_inflate_page(void) hibernate_state = (struct hibernate_zlib_state *)HIBERNATE_HIBALLOC_PAGE; - /* Set up the stream for inflate */ + /* Set up the stream for RLE code inflate */ + hibernate_state->hib_stream.next_out = (char *)rle; + hibernate_state->hib_stream.avail_out = sizeof(*rle); + + /* Inflate RLE code */ + i = inflate(&hibernate_state->hib_stream, Z_SYNC_FLUSH); + if (i != Z_OK && i != Z_STREAM_END) { + /* + * XXX - this will likely reboot/hang most machines + * since the console output buffer will be unmapped, + * but there's not much else we can do here. + */ + panic("rle inflate stream error"); + } + + if (hibernate_state->hib_stream.avail_out != 0) { + /* + * XXX - this will likely reboot/hang most machines + * since the console output buffer will be unmapped, + * but there's not much else we can do here. + */ + panic("rle short inflate error"); + } + + if (*rle < 0 || *rle > 1024) { + /* + * XXX - this will likely reboot/hang most machines + * since the console output buffer will be unmapped, + * but there's not much else we can do here. + */ + panic("invalid rle count"); + } + + if (i == Z_STREAM_END) + return (1); + + if (*rle != 0) + return (0); + + /* Set up the stream for page inflate */ hibernate_state->hib_stream.next_out = (char *)HIBERNATE_INFLATE_PAGE; hibernate_state->hib_stream.avail_out = PAGE_SIZE; @@ -848,7 +899,7 @@ void hibernate_inflate_region(union hibernate_info *hib, paddr_t dest, paddr_t src, size_t size) { - int end_stream = 0 ; + int end_stream = 0, rle; struct hibernate_zlib_state *hibernate_state; hibernate_state = @@ -872,9 +923,12 @@ hibernate_inflate_region(union hibernate_info *hib, paddr_t dest, } hibernate_flush(); - end_stream = hibernate_inflate_page(); + end_stream = hibernate_inflate_page(&rle); - dest += PAGE_SIZE; + if (rle == 0) + dest += PAGE_SIZE; + else + dest += (rle * PAGE_SIZE); } while (!end_stream); } @@ -1346,6 +1400,71 @@ hibernate_process_chunk(union hibernate_info *hib, chunk->compressed_size); } +/* + * Calculate RLE component for 'inaddr'. Clamps to max RLE pages between + * inaddr and range_end. + */ +int +hibernate_calc_rle(paddr_t inaddr, paddr_t range_end) +{ + int rle; + + rle = uvm_page_rle(inaddr); + KASSERT(rle >= 0 && rle <= MAX_RLE); + + /* Clamp RLE to range end */ + if (rle > 0 && inaddr + (rle * PAGE_SIZE) > range_end) + rle = (range_end - inaddr) / PAGE_SIZE; + + return (rle); +} + +/* + * Write the RLE byte for page at 'inaddr' to the output stream. + * Returns the number of pages to be skipped at 'inaddr'. + */ +int +hibernate_write_rle(union hibernate_info *hib, paddr_t inaddr, + paddr_t range_end, daddr_t *blkctr, + size_t *out_remaining) +{ + int rle, err, *rleloc; + struct hibernate_zlib_state *hibernate_state; + vaddr_t hibernate_io_page = hib->piglet_va + PAGE_SIZE; + + hibernate_state = + (struct hibernate_zlib_state *)HIBERNATE_HIBALLOC_PAGE; + + rle = hibernate_calc_rle(inaddr, range_end); + + rleloc = (int *)hibernate_rle_page + MAX_RLE - 1; + *rleloc = rle; + + /* Deflate the RLE byte into the stream */ + hibernate_deflate(hib, (paddr_t)rleloc, out_remaining); + + /* Did we fill the output page? If so, flush to disk */ + if (*out_remaining == 0) { + if ((err = hib->io_func(hib->dev, *blkctr + hib->image_offset, + (vaddr_t)hibernate_io_page, PAGE_SIZE, HIB_W, + hib->io_page))) { + DPRINTF("hib write error %d\n", err); + return (err); + } + + *blkctr += PAGE_SIZE / DEV_BSIZE; + *out_remaining = PAGE_SIZE; + + /* If we didn't deflate the entire RLE byte, finish it now */ + if (hibernate_state->hib_stream.avail_in != 0) + hibernate_deflate(hib, + (vaddr_t)hibernate_state->hib_stream.next_in, + out_remaining); + } + + return (rle); +} + /* * Write a compressed version of this machine's memory to disk, at the * precalculated swap offset: @@ -1381,7 +1500,7 @@ hibernate_write_chunks(union hibernate_info *hib) struct hibernate_disk_chunk *chunks; vaddr_t hibernate_io_page = hib->piglet_va + PAGE_SIZE; daddr_t blkctr = 0; - int i, err; + int i, rle, err; struct hibernate_zlib_state *hibernate_state; hibernate_state = @@ -1397,8 +1516,10 @@ hibernate_write_chunks(union hibernate_info *hib) */ hibernate_temp_page = (vaddr_t)km_alloc(PAGE_SIZE, &kv_any, &kp_none, &kd_nowait); - if (!hibernate_temp_page) + if (!hibernate_temp_page) { + DPRINTF("out of memory allocating hibernate_temp_page\n"); return (ENOMEM); + } hibernate_copy_page = (vaddr_t)km_alloc(PAGE_SIZE, &kv_any, &kp_none, &kd_nowait); @@ -1407,8 +1528,21 @@ hibernate_write_chunks(union hibernate_info *hib) return (ENOMEM); } + hibernate_rle_page = (vaddr_t)km_alloc(PAGE_SIZE, &kv_any, + &kp_none, &kd_nowait); + if (!hibernate_rle_page) { + DPRINTF("out of memory allocating hibernate_rle_page\n"); + return (ENOMEM); + } + + /* + * Map the utility VAs to the piglet. See the piglet map at the + * top of this file for piglet layout information. + */ pmap_kenter_pa(hibernate_copy_page, - (hib->piglet_pa + 3*PAGE_SIZE), VM_PROT_ALL); + (hib->piglet_pa + 3 * PAGE_SIZE), VM_PROT_ALL); + pmap_kenter_pa(hibernate_rle_page, + (hib->piglet_pa + 28 * PAGE_SIZE), VM_PROT_ALL); pmap_activate(curproc); @@ -1435,6 +1569,9 @@ hibernate_write_chunks(union hibernate_info *hib) } } + uvm_pmr_dirty_everything(); + uvm_pmr_zero_everything(); + /* Compress and write the chunks in the chunktable */ for (i = 0; i < hib->chunk_ctr; i++) { range_base = chunks[i].base; @@ -1458,7 +1595,6 @@ hibernate_write_chunks(union hibernate_info *hib) while (inaddr < range_end) { out_remaining = PAGE_SIZE; while (out_remaining > 0 && inaddr < range_end) { - /* * Adjust for regions that are not evenly * divisible by PAGE_SIZE or overflowed @@ -1469,22 +1605,38 @@ hibernate_write_chunks(union hibernate_info *hib) /* Deflate from temp_inaddr to IO page */ if (inaddr != range_end) { - pmap_kenter_pa(hibernate_temp_page, - inaddr & PMAP_PA_MASK, VM_PROT_ALL); - - pmap_activate(curproc); + if (inaddr % PAGE_SIZE == 0) { + rle = hibernate_write_rle(hib, + inaddr, + range_end, + &blkctr, + &out_remaining); + } + + if (rle == 0) { + pmap_kenter_pa(hibernate_temp_page, + inaddr & PMAP_PA_MASK, + VM_PROT_ALL); + + pmap_activate(curproc); + + bcopy((caddr_t)hibernate_temp_page, + (caddr_t)hibernate_copy_page, + PAGE_SIZE); + inaddr += hibernate_deflate(hib, + temp_inaddr, + &out_remaining); + } else { + inaddr += rle * PAGE_SIZE; + if (inaddr > range_end) + inaddr = range_end; + } - bcopy((caddr_t)hibernate_temp_page, - (caddr_t)hibernate_copy_page, - PAGE_SIZE); - inaddr += hibernate_deflate(hib, - temp_inaddr, &out_remaining); } if (out_remaining == 0) { /* Filled up the page */ - nblocks = - PAGE_SIZE / DEV_BSIZE; + nblocks = PAGE_SIZE / DEV_BSIZE; if ((err = hib->io_func(hib->dev, blkctr + hib->image_offset, @@ -1576,7 +1728,11 @@ hibernate_zlib_reset(union hibernate_info *hib, int deflate) if (!deflate) pva = (char *)((paddr_t)pva & (PIGLET_PAGE_MASK)); - hibernate_zlib_start = (vaddr_t)(pva + (28 * PAGE_SIZE)); + /* + * See piglet layout information at the start of this file for + * information on the zlib page assignments. + */ + hibernate_zlib_start = (vaddr_t)(pva + (29 * PAGE_SIZE)); hibernate_zlib_size = 80 * PAGE_SIZE; memset((void *)hibernate_zlib_start, 0, hibernate_zlib_size); @@ -1913,6 +2069,8 @@ hibernate_free(void) pmap_kremove(hibernate_copy_page, PAGE_SIZE); if (hibernate_temp_page) pmap_kremove(hibernate_temp_page, PAGE_SIZE); + if (hibernate_rle_page) + pmap_kremove(hibernate_rle_page, PAGE_SIZE); pmap_update(pmap_kernel()); @@ -1922,8 +2080,12 @@ hibernate_free(void) if (hibernate_temp_page) km_free((void *)hibernate_temp_page, PAGE_SIZE, &kv_any, &kp_none); + if (hibernate_rle_page) + km_free((void *)hibernate_rle_page, PAGE_SIZE, + &kv_any, &kp_none); global_piglet_va = 0; hibernate_copy_page = 0; hibernate_temp_page = 0; + hibernate_rle_page = 0; } diff --git a/sys/sys/hibernate.h b/sys/sys/hibernate.h index 0def3c7f7e4..e58b0ed4fa6 100644 --- a/sys/sys/hibernate.h +++ b/sys/sys/hibernate.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate.h,v 1.34 2014/07/12 09:02:24 kettenis Exp $ */ +/* $OpenBSD: hibernate.h,v 1.35 2014/07/16 07:42:51 mlarkin Exp $ */ /* * Copyright (c) 2011 Ariane van der Steldt @@ -126,7 +126,7 @@ void hibernate_inflate_region(union hibernate_info *, paddr_t, paddr_t, size_t hibernate_deflate(union hibernate_info *, paddr_t, size_t *); void hibernate_process_chunk(union hibernate_info *, struct hibernate_disk_chunk *, paddr_t); -int hibernate_inflate_page(void); +int hibernate_inflate_page(int *); int hibernate_block_io(union hibernate_info *, daddr_t, size_t, vaddr_t, int); int hibernate_write_signature(union hibernate_info *);