diff options
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/hibernate_machdep.c | 33 | ||||
-rw-r--r-- | sys/arch/i386/i386/hibernate_machdep.c | 33 | ||||
-rw-r--r-- | sys/kern/subr_hibernate.c | 92 |
3 files changed, 83 insertions, 75 deletions
diff --git a/sys/arch/amd64/amd64/hibernate_machdep.c b/sys/arch/amd64/amd64/hibernate_machdep.c index cee07d8efc1..167f08d9fcd 100644 --- a/sys/arch/amd64/amd64/hibernate_machdep.c +++ b/sys/arch/amd64/amd64/hibernate_machdep.c @@ -63,6 +63,8 @@ extern struct hibernate_state *hibernate_state; /* * amd64 MD Hibernate functions + * + * see amd64 hibernate.h for lowmem layout used during hibernate */ /* @@ -322,21 +324,6 @@ hibernate_populate_resume_pt(union hibernate_info *hib_info, /* * MD-specific resume preparation (creating resume time pagetables, * stacks, etc). - * - * On amd64, we use the piglet whose address is contained in hib_info - * as per the following layout: - * - * offset from piglet base use - * ----------------------- -------------------- - * 0 i/o allocation area - * PAGE_SIZE i/o read area - * 2*PAGE_SIZE temp/scratch page - * 5*PAGE_SIZE resume stack - * 6*PAGE_SIZE hiballoc arena - * 7*PAGE_SIZE to 87*PAGE_SIZE zlib inflate area - * ... - * HIBERNATE_CHUNK_SIZE chunk table - * 2*HIBERNATE_CHUNK_SIZE bounce/copy area */ void hibernate_prepare_resume_machdep(union hibernate_info *hib_info) @@ -345,15 +332,13 @@ hibernate_prepare_resume_machdep(union hibernate_info *hib_info) vaddr_t va; /* - * At this point, we are sure that the piglet's phys - * space is going to have been unused by the suspending - * kernel, but the vaddrs used by the suspending kernel - * may or may not be available to us here in the - * resuming kernel, so we allocate a new range of VAs - * for the piglet. Those VAs will be temporary and will - * cease to exist as soon as we switch to the resume - * PT, so we need to ensure that any VAs required during - * inflate are also entered into that map. + * At this point, we are sure that the piglet's phys space is going to + * have been unused by the suspending kernel, but the vaddrs used by + * the suspending kernel may or may not be available to us here in the + * resuming kernel, so we allocate a new range of VAs for the piglet. + * Those VAs will be temporary and will cease to exist as soon as we + * switch to the resume PT, so we need to ensure that any VAs required + * during inflate are also entered into that map. */ hib_info->piglet_va = (vaddr_t)km_alloc(HIBERNATE_CHUNK_SIZE*3, diff --git a/sys/arch/i386/i386/hibernate_machdep.c b/sys/arch/i386/i386/hibernate_machdep.c index 699dd615e85..8b8d2dd79a4 100644 --- a/sys/arch/i386/i386/hibernate_machdep.c +++ b/sys/arch/i386/i386/hibernate_machdep.c @@ -62,6 +62,8 @@ extern struct hibernate_state *hibernate_state; /* * i386 MD Hibernate functions + * + * see i386 hibernate.h for lowmem layout used during hibernate */ /* @@ -266,21 +268,6 @@ hibernate_populate_resume_pt(union hibernate_info *hib_info, /* * MD-specific resume preparation (creating resume time pagetables, * stacks, etc). - * - * On i386, we use the piglet whose address is contained in hib_info - * as per the following layout: - * - * offset from piglet base use - * ----------------------- -------------------- - * 0 i/o allocation area - * PAGE_SIZE i/o read area - * 2*PAGE_SIZE temp/scratch page - * 5*PAGE_SIZE resume stack - * 6*PAGE_SIZE hiballoc arena - * 7*PAGE_SIZE to 87*PAGE_SIZE zlib inflate area - * ... - * HIBERNATE_CHUNK_SIZE chunk table - * 2*HIBERNATE_CHUNK_SIZE bounce/copy area */ void hibernate_prepare_resume_machdep(union hibernate_info *hib_info) @@ -289,15 +276,13 @@ hibernate_prepare_resume_machdep(union hibernate_info *hib_info) vaddr_t va; /* - * At this point, we are sure that the piglet's phys - * space is going to have been unused by the suspending - * kernel, but the vaddrs used by the suspending kernel - * may or may not be available to us here in the - * resuming kernel, so we allocate a new range of VAs - * for the piglet. Those VAs will be temporary and will - * cease to exist as soon as we switch to the resume - * PT, so we need to ensure that any VAs required during - * inflate are also entered into that map. + * At this point, we are sure that the piglet's phys space is going to + * have been unused by the suspending kernel, but the vaddrs used by + * the suspending kernel may or may not be available to us here in the + * resuming kernel, so we allocate a new range of VAs for the piglet. + * Those VAs will be temporary and will cease to exist as soon as we + * switch to the resume PT, so we need to ensure that any VAs required + * during inflate are also entered into that map. */ hib_info->piglet_va = (vaddr_t)km_alloc(HIBERNATE_CHUNK_SIZE*3, diff --git a/sys/kern/subr_hibernate.c b/sys/kern/subr_hibernate.c index 476d4ef3fc7..20358a70b3b 100644 --- a/sys/kern/subr_hibernate.c +++ b/sys/kern/subr_hibernate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_hibernate.c,v 1.51 2013/03/06 08:34:05 mlarkin Exp $ */ +/* $OpenBSD: subr_hibernate.c,v 1.52 2013/03/07 01:26:54 mlarkin Exp $ */ /* * Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl> @@ -33,6 +33,32 @@ #include <uvm/uvm_swap.h> #include <machine/hibernate.h> +/* + * Hibernate piglet layout information + * + * The piglet is a scratch area of memory allocated by the suspending kernel. + * Its phys and virt addrs are recorded in the signature block. The piglet is + * used to guarantee an unused area of memory that can be used by the resuming + * kernel for various things. The piglet is excluded during unpack operations. + * The piglet size is presently 3*HIBERNATE_CHUNK_SIZE (typically 3*4MB). + * + * Offset from piglet_base Purpose + * ---------------------------------------------------------------------------- + * 0 I/O page used during resume + * 1*PAGE_SIZE I/O page used during hibernate suspend + * 2*PAGE_SIZE unused + * 3*PAGE_SIZE copy page used during hibernate suspend + * 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) + * ... unused + * HIBERNATE_CHUNK_SIZE start of hibernate chunk table + * 2*HIBERNATE_CHUNK_SIZE bounce area for chunks being unpacked + * 3*HIBERNATE_CHUNK_SIZE end of piglet + */ + /* Temporary vaddr ranges used during hibernate */ vaddr_t hibernate_temp_page; vaddr_t hibernate_copy_page; @@ -451,7 +477,7 @@ retry: } /* - * Try to coerse the pagedaemon into freeing memory + * Try to coerce the pagedaemon into freeing memory * for the piglet. * * pdaemon_woken is set to prevent the code from @@ -565,8 +591,8 @@ 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 the number of pages in + * Given a physical page address, return the number of pages 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. */ int @@ -660,8 +686,12 @@ get_hibernate_info(union hibernate_info *hiber_info, int suspend) hiber_info->io_page = (void *)hiber_info->piglet_va; /* - * Initialize of the hibernate IO function (for drivers which - * need that) + * Initialization of the hibernate IO function for drivers + * that need to do prep work (such as allocating memory or + * setting up data structures that cannot safely be done + * during suspend without causing side effects). There is + * a matching HIB_DONE call performed after the write is + * completed. */ if (hiber_info->io_func(hiber_info->device, 0, (vaddr_t)NULL, 0, HIB_INIT, hiber_info->io_page)) @@ -683,7 +713,7 @@ get_hibernate_info(union hibernate_info *hiber_info, int suspend) if (get_hibernate_info_md(hiber_info)) goto fail; - /* Calculate memory image location */ + /* Calculate memory image location in swap */ hiber_info->image_offset = dl.d_partitions[1].p_offset + dl.d_partitions[1].p_size - (hiber_info->image_size / hiber_info->secsize) - @@ -747,7 +777,8 @@ hibernate_get_next_rle(void) 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, + * 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("inflate rle error"); @@ -783,16 +814,22 @@ hibernate_inflate_page(void) i = inflate(&hibernate_state->hib_stream, Z_PARTIAL_FLUSH); if (i != Z_OK && i != Z_STREAM_END) { /* - * XXX - this will likely reboot/hang most machines, + * 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("inflate error"); } /* We should always have extracted a full page ... */ - if (hibernate_state->hib_stream.avail_out != 0) + 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("incomplete page"); + } return (i == Z_STREAM_END); } @@ -803,7 +840,8 @@ hibernate_inflate_page(void) * * This function executes while using the resume-time stack * and pmap, and therefore cannot use ddb/printf/etc. Doing so - * will likely hang or reset the machine. + * will likely hang or reset the machine since the console output buffer + * will be unmapped. */ void hibernate_inflate_region(union hibernate_info *hiber_info, paddr_t dest, @@ -880,9 +918,6 @@ hibernate_deflate(union hibernate_info *hiber_info, paddr_t src, * Write the hibernation information specified in hiber_info * to the location in swap previously calculated (last block of * swap), called the "signature block". - * - * Write the memory chunk table to the area in swap immediately - * preceding the signature block. */ int hibernate_write_signature(union hibernate_info *hiber_info) @@ -1127,8 +1162,6 @@ hibernate_resume(void) goto fail; } - /* Point of no return ... */ - pmap_kenter_pa(HIBERNATE_HIBALLOC_PAGE, HIBERNATE_HIBALLOC_PAGE, VM_PROT_ALL); pmap_activate(curproc); @@ -1137,11 +1170,15 @@ hibernate_resume(void) hibernate_switch_stack_machdep(); /* - * Image is now in high memory (pig area), copy to correct location - * in memory. We'll eventually end up copying on top of ourself, but - * we are assured the kernel code here is the same between the - * hibernated and resuming kernel, and we are running on our own - * stack, so the overwrite is ok. + * Point of no return. Once we pass this point, only kernel code can + * be accessed. No global variables or other kernel data structures + * are guaranteed to be coherent after unpack starts. + * + * The image is now in high memory (pig area), we unpack from the pig + * to the correct location in memory. We'll eventually end up copying + * on top of ourself, but we are assured the kernel code here is the + * same between the hibernated and resuming kernel, and we are running + * on our own stack, so the overwrite is ok. */ hibernate_unpack_image(&disk_hiber_info); @@ -1159,10 +1196,6 @@ fail: /* * Unpack image from pig area to original location by looping through the * list of output chunks in the order they should be restored (fchunks). - * This ordering is used to avoid having inflate overwrite a chunk in the - * middle of processing that chunk. This will, of course, happen during the - * final output chunk, where we copy the chunk to the piglet area first, - * before inflating. */ void hibernate_unpack_image(union hibernate_info *hiber_info) @@ -1271,7 +1304,7 @@ hibernate_process_chunk(union hibernate_info *hiber_info, * devices are quiesced/suspended, interrupts are off, and cold has * been set. This means that there can be no side effects once the * write has started, and the write function itself can also have no - * side effects. This also means no printfs are permitted (since it + * side effects. This also means no printfs are permitted (since printf * has side effects.) */ int @@ -1292,6 +1325,7 @@ hibernate_write_chunks(union hibernate_info *hiber_info) /* * Allocate VA for the temp and copy page. + * * These will become part of the suspended kernel and will * be freed in hibernate_free, upon resume. */ @@ -1835,6 +1869,10 @@ hibernate_suspend(void) /* Allow the disk to settle */ delay(500000); + /* + * Give the device-specific I/O function a notification that we're + * done, and that it can clean up or shutdown as needed. + */ hib_info.io_func(hib_info.device, 0, (vaddr_t)NULL, 0, HIB_DONE, hib_info.io_page); |