Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86, trampoline: Use the unified trampoline setup for ACPI wakeup

Use the unified trampoline allocation setup to allocate and install
the ACPI wakeup code in low memory.

Signed-off-by: H. Peter Anvin <hpa@linux.intel.com>
LKML-Reference: <4D5DFBE4.7090104@intel.com>
Cc: Rafael J. Wysocki <rjw@sisk.pl>
Cc: Matthieu Castet <castet.matthieu@free.fr>
Cc: Stephen Rothwell <sfr@canb.auug.org.au>

+69 -108
+3 -1
arch/x86/include/asm/acpi.h
··· 29 29 #include <asm/processor.h> 30 30 #include <asm/mmu.h> 31 31 #include <asm/mpspec.h> 32 + #include <asm/trampoline.h> 32 33 33 34 #define COMPILER_DEPENDENT_INT64 long long 34 35 #define COMPILER_DEPENDENT_UINT64 unsigned long long ··· 117 116 extern int acpi_save_state_mem(void); 118 117 extern void acpi_restore_state_mem(void); 119 118 120 - extern unsigned long acpi_wakeup_address; 119 + extern const unsigned char acpi_wakeup_code[]; 120 + #define acpi_wakeup_address (__pa(TRAMPOLINE_SYM(acpi_wakeup_code))) 121 121 122 122 /* early initialization routine */ 123 123 extern void acpi_reserve_wakeup_memory(void);
+22 -11
arch/x86/include/asm/trampoline.h
··· 3 3 4 4 #ifndef __ASSEMBLY__ 5 5 6 - #ifdef CONFIG_X86_TRAMPOLINE 6 + #include <linux/types.h> 7 + #include <asm/io.h> 8 + 7 9 /* 8 - * Trampoline 80x86 program as an array. 10 + * Trampoline 80x86 program as an array. These are in the init rodata 11 + * segment, but that's okay, because we only care about the relative 12 + * addresses of the symbols. 9 13 */ 10 - extern const unsigned char trampoline_data []; 11 - extern const unsigned char trampoline_end []; 12 - extern unsigned char *trampoline_base; 14 + extern const unsigned char x86_trampoline_start []; 15 + extern const unsigned char x86_trampoline_end []; 16 + extern unsigned char *x86_trampoline_base; 13 17 14 18 extern unsigned long init_rsp; 15 19 extern unsigned long initial_code; 16 20 extern unsigned long initial_gs; 17 21 18 - #define TRAMPOLINE_SIZE roundup(trampoline_end - trampoline_data, PAGE_SIZE) 22 + extern void __init setup_trampolines(void); 19 23 20 - extern unsigned long setup_trampoline(void); 21 - extern void __init reserve_trampoline_memory(void); 22 - #else 23 - static inline void reserve_trampoline_memory(void) {} 24 - #endif /* CONFIG_X86_TRAMPOLINE */ 24 + extern const unsigned char trampoline_data[]; 25 + extern const unsigned char trampoline_status[]; 26 + 27 + #define TRAMPOLINE_SYM(x) \ 28 + ((void *)(x86_trampoline_base + \ 29 + ((const unsigned char *)(x) - x86_trampoline_start))) 30 + 31 + /* Address of the SMP trampoline */ 32 + static inline unsigned long trampoline_address(void) 33 + { 34 + return virt_to_phys(TRAMPOLINE_SYM(trampoline_data)); 35 + } 25 36 26 37 #endif /* __ASSEMBLY__ */ 27 38
+14 -7
arch/x86/kernel/acpi/realmode/wakeup.S
··· 6 6 #include <asm/page_types.h> 7 7 #include <asm/pgtable_types.h> 8 8 #include <asm/processor-flags.h> 9 + #include "wakeup.h" 9 10 10 11 .code16 11 - .section ".header", "a" 12 + .section ".jump", "ax" 13 + .globl _start 14 + _start: 15 + cli 16 + jmp wakeup_code 12 17 13 18 /* This should match the structure in wakeup.h */ 19 + .section ".header", "a" 14 20 .globl wakeup_header 15 21 wakeup_header: 16 22 video_mode: .short 0 /* Video mode number */ ··· 36 30 wakeup_jmp_off: .word 3f 37 31 wakeup_jmp_seg: .word 0 38 32 wakeup_gdt: .quad 0, 0, 0 39 - signature: .long 0x51ee1111 33 + signature: .long WAKEUP_HEADER_SIGNATURE 40 34 41 35 .text 42 - .globl _start 43 36 .code16 44 37 wakeup_code: 45 - _start: 46 - cli 47 38 cld 48 39 49 40 /* Apparently some dimwit BIOS programmers don't know how to ··· 80 77 81 78 /* Check header signature... */ 82 79 movl signature, %eax 83 - cmpl $0x51ee1111, %eax 80 + cmpl $WAKEUP_HEADER_SIGNATURE, %eax 84 81 jne bogus_real_magic 85 82 86 83 /* Check we really have everything... */ 87 84 movl end_signature, %eax 88 - cmpl $0x65a22c82, %eax 85 + cmpl $WAKEUP_END_SIGNATURE, %eax 89 86 jne bogus_real_magic 90 87 91 88 /* Call the C code */ ··· 150 147 wakeup_stack: 151 148 .space 2048 152 149 wakeup_stack_end: 150 + 151 + .section ".signature","a" 152 + end_signature: 153 + .long WAKEUP_END_SIGNATURE
+3 -2
arch/x86/kernel/acpi/realmode/wakeup.h
··· 35 35 extern struct wakeup_header wakeup_header; 36 36 #endif 37 37 38 - #define HEADER_OFFSET 0x3f00 39 - #define WAKEUP_SIZE 0x4000 38 + #define WAKEUP_HEADER_OFFSET 8 39 + #define WAKEUP_HEADER_SIGNATURE 0x51ee1111 40 + #define WAKEUP_END_SIGNATURE 0x65a22c82 40 41 41 42 #endif /* ARCH_X86_KERNEL_ACPI_RM_WAKEUP_H */
+13 -15
arch/x86/kernel/acpi/realmode/wakeup.lds.S
··· 13 13 SECTIONS 14 14 { 15 15 . = 0; 16 + .jump : { 17 + *(.jump) 18 + } = 0x90909090 19 + 20 + . = WAKEUP_HEADER_OFFSET; 21 + .header : { 22 + *(.header) 23 + } 24 + 25 + . = ALIGN(16); 16 26 .text : { 17 27 *(.text*) 18 - } 28 + } = 0x90909090 19 29 20 30 . = ALIGN(16); 21 31 .rodata : { ··· 43 33 *(.data*) 44 34 } 45 35 46 - .signature : { 47 - end_signature = .; 48 - LONG(0x65a22c82) 49 - } 50 - 51 36 . = ALIGN(16); 52 37 .bss : { 53 38 __bss_start = .; ··· 50 45 __bss_end = .; 51 46 } 52 47 53 - . = HEADER_OFFSET; 54 - .header : { 55 - *(.header) 48 + .signature : { 49 + *(.signature) 56 50 } 57 51 58 - . = ALIGN(16); 59 52 _end = .; 60 53 61 54 /DISCARD/ : { 62 55 *(.note*) 63 56 } 64 - 65 - /* 66 - * The ASSERT() sink to . is intentional, for binutils 2.14 compatibility: 67 - */ 68 - . = ASSERT(_end <= WAKEUP_SIZE, "Wakeup too big!"); 69 57 }
+7 -58
arch/x86/kernel/acpi/sleep.c
··· 18 18 #include "realmode/wakeup.h" 19 19 #include "sleep.h" 20 20 21 - unsigned long acpi_wakeup_address; 22 21 unsigned long acpi_realmode_flags; 23 - 24 - /* address in low memory of the wakeup routine. */ 25 - static unsigned long acpi_realmode; 26 22 27 23 #if defined(CONFIG_SMP) && defined(CONFIG_64BIT) 28 24 static char temp_stack[4096]; ··· 29 33 * 30 34 * Create an identity mapped page table and copy the wakeup routine to 31 35 * low memory. 32 - * 33 - * Note that this is too late to change acpi_wakeup_address. 34 36 */ 35 37 int acpi_save_state_mem(void) 36 38 { 37 39 struct wakeup_header *header; 40 + /* address in low memory of the wakeup routine. */ 41 + char *acpi_realmode; 38 42 39 - if (!acpi_realmode) { 40 - printk(KERN_ERR "Could not allocate memory during boot, " 41 - "S3 disabled\n"); 42 - return -ENOMEM; 43 - } 44 - memcpy((void *)acpi_realmode, &wakeup_code_start, WAKEUP_SIZE); 43 + acpi_realmode = TRAMPOLINE_SYM(acpi_wakeup_code); 45 44 46 - header = (struct wakeup_header *)(acpi_realmode + HEADER_OFFSET); 47 - if (header->signature != 0x51ee1111) { 45 + header = (struct wakeup_header *)(acpi_realmode + WAKEUP_HEADER_OFFSET); 46 + if (header->signature != WAKEUP_HEADER_SIGNATURE) { 48 47 printk(KERN_ERR "wakeup header does not match\n"); 49 48 return -EINVAL; 50 49 } ··· 59 68 /* GDT[0]: GDT self-pointer */ 60 69 header->wakeup_gdt[0] = 61 70 (u64)(sizeof(header->wakeup_gdt) - 1) + 62 - ((u64)(acpi_wakeup_address + 63 - ((char *)&header->wakeup_gdt - (char *)acpi_realmode)) 64 - << 16); 71 + ((u64)__pa(&header->wakeup_gdt) << 16); 65 72 /* GDT[1]: big real mode-like code segment */ 66 73 header->wakeup_gdt[1] = 67 74 GDT_ENTRY(0x809b, acpi_wakeup_address, 0xfffff); ··· 85 96 header->pmode_cr3 = (u32)__pa(&initial_page_table); 86 97 saved_magic = 0x12345678; 87 98 #else /* CONFIG_64BIT */ 88 - header->trampoline_segment = setup_trampoline() >> 4; 99 + header->trampoline_segment = trampoline_address() >> 4; 89 100 #ifdef CONFIG_SMP 90 101 stack_start = (unsigned long)temp_stack + sizeof(temp_stack); 91 102 early_gdt_descr.address = ··· 105 116 void acpi_restore_state_mem(void) 106 117 { 107 118 } 108 - 109 - 110 - /** 111 - * acpi_reserve_wakeup_memory - do _very_ early ACPI initialisation 112 - * 113 - * We allocate a page from the first 1MB of memory for the wakeup 114 - * routine for when we come back from a sleep state. The 115 - * runtime allocator allows specification of <16MB pages, but not 116 - * <1MB pages. 117 - */ 118 - void __init acpi_reserve_wakeup_memory(void) 119 - { 120 - phys_addr_t mem; 121 - 122 - if ((&wakeup_code_end - &wakeup_code_start) > WAKEUP_SIZE) { 123 - printk(KERN_ERR 124 - "ACPI: Wakeup code way too big, S3 disabled.\n"); 125 - return; 126 - } 127 - 128 - mem = memblock_find_in_range(0, 1<<20, WAKEUP_SIZE, PAGE_SIZE); 129 - 130 - if (mem == MEMBLOCK_ERROR) { 131 - printk(KERN_ERR "ACPI: Cannot allocate lowmem, S3 disabled.\n"); 132 - return; 133 - } 134 - acpi_realmode = (unsigned long) phys_to_virt(mem); 135 - acpi_wakeup_address = mem; 136 - memblock_x86_reserve_range(mem, mem + WAKEUP_SIZE, "ACPI WAKEUP"); 137 - } 138 - 139 - int __init acpi_configure_wakeup_memory(void) 140 - { 141 - if (acpi_realmode) 142 - set_memory_x(acpi_realmode, WAKEUP_SIZE >> PAGE_SHIFT); 143 - 144 - return 0; 145 - } 146 - arch_initcall(acpi_configure_wakeup_memory); 147 - 148 119 149 120 static int __init acpi_sleep_setup(char *str) 150 121 {
-3
arch/x86/kernel/acpi/sleep.h
··· 4 4 5 5 #include <asm/trampoline.h> 6 6 7 - extern char wakeup_code_start, wakeup_code_end; 8 - 9 7 extern unsigned long saved_video_mode; 10 8 extern long saved_magic; 11 9 12 10 extern int wakeup_pmode_return; 13 - extern char swsusp_pg_dir[PAGE_SIZE]; 14 11 15 12 extern unsigned long acpi_copy_wakeup_routine(unsigned long); 16 13 extern void wakeup_long64(void);
+6 -4
arch/x86/kernel/acpi/wakeup_rm.S
··· 2 2 * Wrapper script for the realmode binary as a transport object 3 3 * before copying to low memory. 4 4 */ 5 - .section ".rodata","a" 6 - .globl wakeup_code_start, wakeup_code_end 7 - wakeup_code_start: 5 + #include <asm/page_types.h> 6 + 7 + .section ".x86_trampoline","a" 8 + .balign PAGE_SIZE 9 + .globl acpi_wakeup_code 10 + acpi_wakeup_code: 8 11 .incbin "arch/x86/kernel/acpi/realmode/wakeup.bin" 9 - wakeup_code_end: 10 12 .size wakeup_code_start, .-wakeup_code_start
-7
arch/x86/kernel/setup.c
··· 937 937 938 938 setup_trampolines(); 939 939 940 - #ifdef CONFIG_ACPI_SLEEP 941 - /* 942 - * Reserve low memory region for sleep support. 943 - * even before init_memory_mapping 944 - */ 945 - acpi_reserve_wakeup_memory(); 946 - #endif 947 940 init_gbpages(); 948 941 949 942 /* max_pfn_mapped is updated here */
+1
drivers/acpi/sleep.c
··· 16 16 #include <linux/device.h> 17 17 #include <linux/suspend.h> 18 18 #include <linux/reboot.h> 19 + #include <linux/acpi.h> 19 20 20 21 #include <asm/io.h> 21 22