diff options
author | Mike Larkin <mlarkin@cvs.openbsd.org> | 2018-06-21 07:33:31 +0000 |
---|---|---|
committer | Mike Larkin <mlarkin@cvs.openbsd.org> | 2018-06-21 07:33:31 +0000 |
commit | 3a21859a0c4c8bde27939cc91e4704e1d67f0ee5 (patch) | |
tree | e303583096d20924446c53b981eb1b939c923f44 /sys | |
parent | 0b2de1b550db093ace9067015042a01d0d2d0e44 (diff) |
Save and restore retguard area during hibernate unpack. This copies the
original retguard data to the piglet and bcopys it back in place
immediately before resuming via the ACPI Sx trampoline.
ok deraadt, guenther, tested by many.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/arch/amd64/amd64/acpi_wakecode.S | 32 | ||||
-rw-r--r-- | sys/arch/amd64/amd64/hibernate_machdep.c | 20 | ||||
-rw-r--r-- | sys/arch/amd64/include/hibernate.h | 4 | ||||
-rw-r--r-- | sys/arch/i386/i386/hibernate_machdep.c | 3 | ||||
-rw-r--r-- | sys/arch/i386/include/hibernate.h | 4 | ||||
-rw-r--r-- | sys/arch/loongson/include/hibernate.h | 4 | ||||
-rw-r--r-- | sys/kern/subr_hibernate.c | 33 | ||||
-rw-r--r-- | sys/sys/hibernate.h | 7 |
8 files changed, 87 insertions, 20 deletions
diff --git a/sys/arch/amd64/amd64/acpi_wakecode.S b/sys/arch/amd64/amd64/acpi_wakecode.S index 4eabf3e23c7..a9d3f4e778e 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.42 2018/05/22 15:55:30 guenther Exp $ */ +/* $OpenBSD: acpi_wakecode.S,v 1.43 2018/06/21 07:33:30 mlarkin Exp $ */ /* * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org> * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> @@ -359,6 +359,36 @@ _C_LABEL(acpi_long_mode_resume): */ .code64 NENTRY(hibernate_resume_machdep) + /* + * On resume time page table, switch temporarily to the suspended + * kernel's old page table (needed to access the suspended kernel's + * retguard area) + */ + movq .Lacpi_saved_cr3, %rax + movq %rax, %cr3 + + /* + * Now back on suspended kernel's page tables. Need to copy + * into rodata, so instead of fixing up the perms here and + * resetting them later, temporarily disable CR0.WP to allow + * us to write. + */ + movq %cr0, %rax + andq $(~CR0_WP), %rax + movq %rax, %cr0 + + movq %rdi, %rsi + movq $__retguard_start, %rdi + movq $__retguard_end, %rcx + subq %rdi, %rcx + shrq $0x3, %rcx + rep movsq + + /* Reenable CR0.WP */ + movq %cr0, %rax + orq $(CR0_WP), %rax + movq %rax, %cr0 + cli /* Jump to the identity mapped version of ourself */ mov $.Lhibernate_resume_vector_2, %rax diff --git a/sys/arch/amd64/amd64/hibernate_machdep.c b/sys/arch/amd64/amd64/hibernate_machdep.c index c1d7b6a8a0e..f25fe027dde 100644 --- a/sys/arch/amd64/amd64/hibernate_machdep.c +++ b/sys/arch/amd64/amd64/hibernate_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate_machdep.c,v 1.41 2018/03/20 04:18:40 jmatthew Exp $ */ +/* $OpenBSD: hibernate_machdep.c,v 1.42 2018/06/21 07:33:30 mlarkin Exp $ */ /* * Copyright (c) 2012 Mike Larkin <mlarkin@openbsd.org> @@ -413,17 +413,27 @@ hibernate_populate_resume_pt(union hibernate_info *hib_info, /* * During inflate, certain pages that contain our bookkeeping information - * (eg, the chunk table, scratch pages, etc) need to be skipped over and - * not inflated into. + * (eg, the chunk table, scratch pages, retguard region, etc) need to be + * skipped over and not inflated into. * - * Returns 1 if the physical page at dest should be skipped, 0 otherwise + * Return values: + * HIB_MOVE: if the physical page at dest should be moved to the retguard save + * region in the piglet + * HIB_SKIP: if the physical page at dest should be skipped + * 0: otherwise (no special treatment needed) */ int hibernate_inflate_skip(union hibernate_info *hib_info, paddr_t dest) { + extern char __retguard_start_phys, __retguard_end_phys; + if (dest >= hib_info->piglet_pa && dest <= (hib_info->piglet_pa + 4 * HIBERNATE_CHUNK_SIZE)) - return (1); + return (HIB_SKIP); + + if (dest >= ((paddr_t)&__retguard_start_phys) && + dest <= ((paddr_t)&__retguard_end_phys)) + return (HIB_MOVE); return (0); } diff --git a/sys/arch/amd64/include/hibernate.h b/sys/arch/amd64/include/hibernate.h index cfcb812ff78..3052bff8729 100644 --- a/sys/arch/amd64/include/hibernate.h +++ b/sys/arch/amd64/include/hibernate.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate.h,v 1.6 2014/07/09 11:37:16 mlarkin Exp $ */ +/* $OpenBSD: hibernate.h,v 1.7 2018/06/21 07:33:30 mlarkin Exp $ */ /* * Copyright (c) 2011 Mike Larkin <mlarkin@openbsd.org> @@ -26,7 +26,7 @@ void hibernate_enter_resume_mapping(vaddr_t, paddr_t, int); int hibernate_inflate_skip(union hibernate_info *, paddr_t); int hibernate_suspend(void); void hibernate_switch_stack_machdep(void); -void hibernate_resume_machdep(void); +void hibernate_resume_machdep(vaddr_t); void hibernate_activate_resume_pt_machdep(void); void hibernate_enable_intr_machdep(void); void hibernate_disable_intr_machdep(void); diff --git a/sys/arch/i386/i386/hibernate_machdep.c b/sys/arch/i386/i386/hibernate_machdep.c index f98d6c5a49e..c8164705183 100644 --- a/sys/arch/i386/i386/hibernate_machdep.c +++ b/sys/arch/i386/i386/hibernate_machdep.c @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate_machdep.c,v 1.51 2018/03/20 04:18:40 jmatthew Exp $ */ +/* $OpenBSD: hibernate_machdep.c,v 1.52 2018/06/21 07:33:30 mlarkin Exp $ */ /* * Copyright (c) 2011 Mike Larkin <mlarkin@openbsd.org> @@ -52,7 +52,6 @@ void hibernate_enter_resume_4k_pte(vaddr_t, paddr_t); void hibernate_enter_resume_4k_pde(vaddr_t); void hibernate_enter_resume_4m_pde(vaddr_t, paddr_t); -extern void hibernate_resume_machdep(void); extern void hibernate_flush(void); extern caddr_t start, end; extern int ndumpmem; diff --git a/sys/arch/i386/include/hibernate.h b/sys/arch/i386/include/hibernate.h index f170ed82992..6448e7dd902 100644 --- a/sys/arch/i386/include/hibernate.h +++ b/sys/arch/i386/include/hibernate.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate.h,v 1.9 2014/05/31 06:30:16 mlarkin Exp $ */ +/* $OpenBSD: hibernate.h,v 1.10 2018/06/21 07:33:30 mlarkin Exp $ */ /* * Copyright (c) 2011 Mike Larkin <mlarkin@openbsd.org> @@ -26,7 +26,7 @@ void hibernate_enter_resume_mapping(vaddr_t, paddr_t, int); int hibernate_inflate_skip(union hibernate_info *, paddr_t); int hibernate_suspend(void); void hibernate_switch_stack_machdep(void); -void hibernate_resume_machdep(void); +void hibernate_resume_machdep(vaddr_t); void hibernate_activate_resume_pt_machdep(void); void hibernate_enable_intr_machdep(void); void hibernate_disable_intr_machdep(void); diff --git a/sys/arch/loongson/include/hibernate.h b/sys/arch/loongson/include/hibernate.h index bd267aa0a13..497a278971e 100644 --- a/sys/arch/loongson/include/hibernate.h +++ b/sys/arch/loongson/include/hibernate.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate.h,v 1.2 2014/05/31 06:30:16 mlarkin Exp $ */ +/* $OpenBSD: hibernate.h,v 1.3 2018/06/21 07:33:30 mlarkin Exp $ */ /* * Copyright (c) 2013 Paul Irofti. @@ -27,7 +27,7 @@ void hibernate_enter_resume_mapping(vaddr_t, paddr_t, int); int hibernate_inflate_skip(union hibernate_info *, paddr_t); int hibernate_suspend(void); void hibernate_switch_stack_machdep(void); -void hibernate_resume_machdep(void); +void hibernate_resume_machdep(vaddr_t); void hibernate_activate_resume_pt_machdep(void); void hibernate_enable_intr_machdep(void); void hibernate_disable_intr_machdep(void); diff --git a/sys/kern/subr_hibernate.c b/sys/kern/subr_hibernate.c index 3c946e8ea75..05dec26e810 100644 --- a/sys/kern/subr_hibernate.c +++ b/sys/kern/subr_hibernate.c @@ -1,4 +1,4 @@ -/* $OpenBSD: subr_hibernate.c,v 1.123 2017/08/17 06:50:41 mlarkin Exp $ */ +/* $OpenBSD: subr_hibernate.c,v 1.124 2018/06/21 07:33:30 mlarkin Exp $ */ /* * Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl> @@ -55,6 +55,7 @@ * 29*PAGE_SIZE start of hiballoc area * 30*PAGE_SIZE preserved entropy * 110*PAGE_SIZE end of hiballoc area (80 pages) + * 366*PAGE_SIZE end of retguard preservation region (256 pages) * ... unused * HIBERNATE_CHUNK_SIZE start of hibernate chunk table * 2*HIBERNATE_CHUNK_SIZE bounce area for chunks being unpacked @@ -776,7 +777,7 @@ void hibernate_inflate_region(union hibernate_info *hib, paddr_t dest, paddr_t src, size_t size) { - int end_stream = 0, rle; + int end_stream = 0, rle, skip; struct hibernate_zlib_state *hibernate_state; hibernate_state = @@ -790,10 +791,22 @@ hibernate_inflate_region(union hibernate_info *hib, paddr_t dest, * Is this a special page? If yes, redirect the * inflate output to a scratch page (eg, discard it) */ - if (hibernate_inflate_skip(hib, dest)) { + skip = hibernate_inflate_skip(hib, dest); + if (skip == HIB_SKIP) { hibernate_enter_resume_mapping( HIBERNATE_INFLATE_PAGE, HIBERNATE_INFLATE_PAGE, 0); + } else if (skip == HIB_MOVE) { + /* + * Special case : retguard region. This gets moved + * temporarily into the piglet region and copied into + * place immediately before resume + */ + hibernate_enter_resume_mapping( + HIBERNATE_INFLATE_PAGE, + hib->piglet_pa + (110 * PAGE_SIZE) + + hib->retguard_ofs, 0); + hib->retguard_ofs += PAGE_SIZE; } else { hibernate_enter_resume_mapping( HIBERNATE_INFLATE_PAGE, dest, 0); @@ -1230,6 +1243,7 @@ hibernate_unpack_image(union hibernate_info *hib) /* Can't use hiber_info that's passed in after this point */ bcopy(hib, &local_hib, sizeof(union hibernate_info)); + local_hib.retguard_ofs = 0; /* VA == PA */ local_hib.piglet_va = local_hib.piglet_pa; @@ -1262,9 +1276,18 @@ hibernate_unpack_image(union hibernate_info *hib) /* * Resume the loaded kernel by jumping to the MD resume vector. - * We won't be returning from this call. + * We won't be returning from this call. We pass the location of + * the retguard save area so the MD code can replace it before + * resuming. See the piglet layout at the top of this file for + * more information on the layout of the piglet area. + * + * We use 'global_piglet_va' here since by the time we are at + * this point, we have already unpacked the image, and we want + * the suspended kernel's view of what the piglet was, before + * suspend occurred (since we will need to use that in the retguard + * copy code in hibernate_resume_machdep.) */ - hibernate_resume_machdep(); + hibernate_resume_machdep(global_piglet_va + (110 * PAGE_SIZE)); } /* diff --git a/sys/sys/hibernate.h b/sys/sys/hibernate.h index ff960101f8c..be09102a5e9 100644 --- a/sys/sys/hibernate.h +++ b/sys/sys/hibernate.h @@ -1,4 +1,4 @@ -/* $OpenBSD: hibernate.h,v 1.41 2017/06/22 15:56:29 deraadt Exp $ */ +/* $OpenBSD: hibernate.h,v 1.42 2018/06/21 07:33:30 mlarkin Exp $ */ /* * Copyright (c) 2011 Ariane van der Steldt <ariane@stack.nl> @@ -31,6 +31,10 @@ /* Magic number used to indicate hibernate signature block */ #define HIBERNATE_MAGIC 0x0B5D0B5D +/* Page skip operations used during unpack */ +#define HIB_MOVE 2 +#define HIB_SKIP 1 + struct hiballoc_entry; /* @@ -99,6 +103,7 @@ union hibernate_info { #ifndef NO_PROPOLICE long guard; #endif /* ! NO_PROPOLICE */ + u_int32_t retguard_ofs; }; /* XXX - remove restriction to have this union fit in a single block */ |