aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel
diff options
context:
space:
mode:
authorVivek Goyal <vgoyal@in.ibm.com>2007-05-02 13:27:07 -0400
committerAndi Kleen <andi@basil.nowhere.org>2007-05-02 13:27:07 -0400
commitd8e1baf10d62c06fc52e89137357e54da3d92672 (patch)
tree57bc6d9858e2136ab8492f46badad9bcd9c4beb3 /arch/x86_64/kernel
parent275f55170ec2b5d777b070cb8ab9e5d58e65a2a8 (diff)
[PATCH] x86-64: 64bit ACPI wakeup trampoline
o Moved wakeup_level4_pgt into the wakeup routine so we can run the kernel above 4G. o Now we first go to 64bit mode and continue to run from trampoline and then then start accessing kernel symbols and restore processor context. This enables us to resume even in relocatable kernel context when kernel might not be loaded at physical addr it has been compiled for. o Removed the need for modifying any existing kernel page table. o Increased the size of the wakeup routine to 8K. This is required as wake page tables are on trampoline itself and they got to be at 4K boundary, hence one page is not sufficient. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> Signed-off-by: Vivek Goyal <vgoyal@in.ibm.com> Signed-off-by: Andi Kleen <ak@suse.de>
Diffstat (limited to 'arch/x86_64/kernel')
-rw-r--r--arch/x86_64/kernel/acpi/sleep.c24
-rw-r--r--arch/x86_64/kernel/acpi/wakeup.S59
-rw-r--r--arch/x86_64/kernel/head.S9
3 files changed, 41 insertions, 51 deletions
diff --git a/arch/x86_64/kernel/acpi/sleep.c b/arch/x86_64/kernel/acpi/sleep.c
index e1548fbe95ae..195b7034a148 100644
--- a/arch/x86_64/kernel/acpi/sleep.c
+++ b/arch/x86_64/kernel/acpi/sleep.c
@@ -60,19 +60,6 @@ extern char wakeup_start, wakeup_end;
60 60
61extern unsigned long acpi_copy_wakeup_routine(unsigned long); 61extern unsigned long acpi_copy_wakeup_routine(unsigned long);
62 62
63static pgd_t low_ptr;
64
65static void init_low_mapping(void)
66{
67 pgd_t *slot0 = pgd_offset(current->mm, 0UL);
68 low_ptr = *slot0;
69 /* FIXME: We're playing with the current task's page tables here, which
70 * is potentially dangerous on SMP systems.
71 */
72 set_pgd(slot0, *pgd_offset(current->mm, PAGE_OFFSET));
73 local_flush_tlb();
74}
75
76/** 63/**
77 * acpi_save_state_mem - save kernel state 64 * acpi_save_state_mem - save kernel state
78 * 65 *
@@ -81,8 +68,6 @@ static void init_low_mapping(void)
81 */ 68 */
82int acpi_save_state_mem(void) 69int acpi_save_state_mem(void)
83{ 70{
84 init_low_mapping();
85
86 memcpy((void *)acpi_wakeup_address, &wakeup_start, 71 memcpy((void *)acpi_wakeup_address, &wakeup_start,
87 &wakeup_end - &wakeup_start); 72 &wakeup_end - &wakeup_start);
88 acpi_copy_wakeup_routine(acpi_wakeup_address); 73 acpi_copy_wakeup_routine(acpi_wakeup_address);
@@ -95,8 +80,6 @@ int acpi_save_state_mem(void)
95 */ 80 */
96void acpi_restore_state_mem(void) 81void acpi_restore_state_mem(void)
97{ 82{
98 set_pgd(pgd_offset(current->mm, 0UL), low_ptr);
99 local_flush_tlb();
100} 83}
101 84
102/** 85/**
@@ -109,10 +92,11 @@ void acpi_restore_state_mem(void)
109 */ 92 */
110void __init acpi_reserve_bootmem(void) 93void __init acpi_reserve_bootmem(void)
111{ 94{
112 acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE); 95 acpi_wakeup_address = (unsigned long)alloc_bootmem_low(PAGE_SIZE*2);
113 if ((&wakeup_end - &wakeup_start) > PAGE_SIZE) 96 if ((&wakeup_end - &wakeup_start) > (PAGE_SIZE*2))
114 printk(KERN_CRIT 97 printk(KERN_CRIT
115 "ACPI: Wakeup code way too big, will crash on attempt to suspend\n"); 98 "ACPI: Wakeup code way too big, will crash on attempt"
99 " to suspend\n");
116} 100}
117 101
118static int __init acpi_sleep_setup(char *str) 102static int __init acpi_sleep_setup(char *str)
diff --git a/arch/x86_64/kernel/acpi/wakeup.S b/arch/x86_64/kernel/acpi/wakeup.S
index bd4c6f1a6f32..766cfbcac1db 100644
--- a/arch/x86_64/kernel/acpi/wakeup.S
+++ b/arch/x86_64/kernel/acpi/wakeup.S
@@ -1,6 +1,7 @@
1.text 1.text
2#include <linux/linkage.h> 2#include <linux/linkage.h>
3#include <asm/segment.h> 3#include <asm/segment.h>
4#include <asm/pgtable.h>
4#include <asm/page.h> 5#include <asm/page.h>
5#include <asm/msr.h> 6#include <asm/msr.h>
6 7
@@ -62,12 +63,15 @@ wakeup_code:
62 63
63 movb $0xa2, %al ; outb %al, $0x80 64 movb $0xa2, %al ; outb %al, $0x80
64 65
65 lidt %ds:idt_48a - wakeup_code 66 mov %ds, %ax # Find 32bit wakeup_code addr
66 xorl %eax, %eax 67 movzx %ax, %esi # (Convert %ds:gdt to a liner ptr)
67 movw %ds, %ax # (Convert %ds:gdt to a linear ptr) 68 shll $4, %esi
68 shll $4, %eax 69 # Fix up the vectors
69 addl $(gdta - wakeup_code), %eax 70 addl %esi, wakeup_32_vector - wakeup_code
70 movl %eax, gdt_48a +2 - wakeup_code 71 addl %esi, wakeup_long64_vector - wakeup_code
72 addl %esi, gdt_48a + 2 - wakeup_code # Fixup the gdt pointer
73
74 lidtl %ds:idt_48a - wakeup_code
71 lgdtl %ds:gdt_48a - wakeup_code # load gdt with whatever is 75 lgdtl %ds:gdt_48a - wakeup_code # load gdt with whatever is
72 # appropriate 76 # appropriate
73 77
@@ -80,7 +84,7 @@ wakeup_code:
80 84
81 .balign 4 85 .balign 4
82wakeup_32_vector: 86wakeup_32_vector:
83 .long wakeup_32 - __START_KERNEL_map 87 .long wakeup_32 - wakeup_code
84 .word __KERNEL32_CS, 0 88 .word __KERNEL32_CS, 0
85 89
86 .code32 90 .code32
@@ -103,10 +107,6 @@ wakeup_32:
103 movl $__KERNEL_DS, %eax 107 movl $__KERNEL_DS, %eax
104 movl %eax, %ds 108 movl %eax, %ds
105 109
106 movl saved_magic - __START_KERNEL_map, %eax
107 cmpl $0x9abcdef0, %eax
108 jne bogus_32_magic
109
110 movw $0x0e00 + 'i', %ds:(0xb8012) 110 movw $0x0e00 + 'i', %ds:(0xb8012)
111 movb $0xa8, %al ; outb %al, $0x80; 111 movb $0xa8, %al ; outb %al, $0x80;
112 112
@@ -120,7 +120,7 @@ wakeup_32:
120 movl %eax, %cr4 120 movl %eax, %cr4
121 121
122 /* Setup early boot stage 4 level pagetables */ 122 /* Setup early boot stage 4 level pagetables */
123 movl $(wakeup_level4_pgt - __START_KERNEL_map), %eax 123 leal (wakeup_level4_pgt - wakeup_code)(%esi), %eax
124 movl %eax, %cr3 124 movl %eax, %cr3
125 125
126 /* Enable Long Mode */ 126 /* Enable Long Mode */
@@ -159,11 +159,11 @@ wakeup_32:
159 */ 159 */
160 160
161 /* Finally jump in 64bit mode */ 161 /* Finally jump in 64bit mode */
162 ljmp *(wakeup_long64_vector - __START_KERNEL_map) 162 ljmp *(wakeup_long64_vector - wakeup_code)(%esi)
163 163
164 .balign 4 164 .balign 4
165wakeup_long64_vector: 165wakeup_long64_vector:
166 .long wakeup_long64 - __START_KERNEL_map 166 .long wakeup_long64 - wakeup_code
167 .word __KERNEL_CS, 0 167 .word __KERNEL_CS, 0
168 168
169.code64 169.code64
@@ -178,11 +178,16 @@ wakeup_long64:
178 * addresses where we're currently running on. We have to do that here 178 * addresses where we're currently running on. We have to do that here
179 * because in 32bit we couldn't load a 64bit linear address. 179 * because in 32bit we couldn't load a 64bit linear address.
180 */ 180 */
181 lgdt cpu_gdt_descr - __START_KERNEL_map 181 lgdt cpu_gdt_descr
182 182
183 movw $0x0e00 + 'n', %ds:(0xb8014) 183 movw $0x0e00 + 'n', %ds:(0xb8014)
184 movb $0xa9, %al ; outb %al, $0x80 184 movb $0xa9, %al ; outb %al, $0x80
185 185
186 movq saved_magic, %rax
187 movq $0x123456789abcdef0, %rdx
188 cmpq %rdx, %rax
189 jne bogus_64_magic
190
186 movw $0x0e00 + 'u', %ds:(0xb8016) 191 movw $0x0e00 + 'u', %ds:(0xb8016)
187 192
188 nop 193 nop
@@ -223,20 +228,21 @@ idt_48a:
223gdt_48a: 228gdt_48a:
224 .word 0x800 # gdt limit=2048, 229 .word 0x800 # gdt limit=2048,
225 # 256 GDT entries 230 # 256 GDT entries
226 .word 0, 0 # gdt base (filled in later) 231 .long gdta - wakeup_code # gdt base (relocated in later)
227
228 232
229real_magic: .quad 0 233real_magic: .quad 0
230video_mode: .quad 0 234video_mode: .quad 0
231video_flags: .quad 0 235video_flags: .quad 0
232 236
237.code16
233bogus_real_magic: 238bogus_real_magic:
234 movb $0xba,%al ; outb %al,$0x80 239 movb $0xba,%al ; outb %al,$0x80
235 jmp bogus_real_magic 240 jmp bogus_real_magic
236 241
237bogus_32_magic: 242.code64
243bogus_64_magic:
238 movb $0xb3,%al ; outb %al,$0x80 244 movb $0xb3,%al ; outb %al,$0x80
239 jmp bogus_32_magic 245 jmp bogus_64_magic
240 246
241bogus_cpu: 247bogus_cpu:
242 movb $0xbc,%al ; outb %al,$0x80 248 movb $0xbc,%al ; outb %al,$0x80
@@ -263,6 +269,7 @@ bogus_cpu:
263#define VIDEO_FIRST_V7 0x0900 269#define VIDEO_FIRST_V7 0x0900
264 270
265# Setting of user mode (AX=mode ID) => CF=success 271# Setting of user mode (AX=mode ID) => CF=success
272.code16
266mode_seta: 273mode_seta:
267 movw %ax, %bx 274 movw %ax, %bx
268#if 0 275#if 0
@@ -313,6 +320,13 @@ wakeup_stack_begin: # Stack grows down
313.org 0xff0 320.org 0xff0
314wakeup_stack: # Just below end of page 321wakeup_stack: # Just below end of page
315 322
323.org 0x1000
324ENTRY(wakeup_level4_pgt)
325 .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
326 .fill 510,8,0
327 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
328 .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
329
316ENTRY(wakeup_end) 330ENTRY(wakeup_end)
317 331
318## 332##
@@ -338,9 +352,10 @@ ENTRY(acpi_copy_wakeup_routine)
338 movq $0x123456789abcdef0, %rdx 352 movq $0x123456789abcdef0, %rdx
339 movq %rdx, saved_magic 353 movq %rdx, saved_magic
340 354
341 movl saved_magic - __START_KERNEL_map, %eax 355 movq saved_magic, %rax
342 cmpl $0x9abcdef0, %eax 356 movq $0x123456789abcdef0, %rdx
343 jne bogus_32_magic 357 cmpq %rdx, %rax
358 jne bogus_64_magic
344 359
345 # restore the regs we used 360 # restore the regs we used
346 popq %rdx 361 popq %rdx
diff --git a/arch/x86_64/kernel/head.S b/arch/x86_64/kernel/head.S
index 562d62fbd69f..926aa2197aaa 100644
--- a/arch/x86_64/kernel/head.S
+++ b/arch/x86_64/kernel/head.S
@@ -308,15 +308,6 @@ NEXT_PAGE(level2_kernel_pgt)
308 308
309 .data 309 .data
310 310
311#ifdef CONFIG_ACPI_SLEEP
312 .align PAGE_SIZE
313ENTRY(wakeup_level4_pgt)
314 .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE
315 .fill 510,8,0
316 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */
317 .quad level3_kernel_pgt - __START_KERNEL_map + _KERNPG_TABLE
318#endif
319
320#ifndef CONFIG_HOTPLUG_CPU 311#ifndef CONFIG_HOTPLUG_CPU
321 __INITDATA 312 __INITDATA
322#endif 313#endif