[PATCH] x86-64: wakeup.S misc cleanups

o Various cleanups. One of the main purpose of cleanups is that make
  wakeup.S as close as possible to trampoline.S.

o Following are the changes
	- Indentations for comments.
	- Changed the gdt table to compact form and to resemble the
	  one in trampoline.S
	- Take the jump to 32bit from real mode using ljmpl. Makes code
	  more readable.
	- After enabling long mode, directly take a long jump for 64bit
	  mode. No need to take an extra jump to "reach_comaptibility_mode"
	- Stack is not used after real mode. So don't load stack in
 	  32 bit mode.
	- No need to enable PGE here.
	- No need to do extra EFER read, anyway we trash the read contents.
	- No need to enable system call (EFER_SCE). Anyway it will be
	  enabled when original EFER is restored.
	- No need to set MP, ET, NE, WP, AM bits in cr0. Very soon we will
  	  reload the original cr0 while restroing the processor state.

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>
This commit is contained in:
Vivek Goyal 2007-05-02 19:27:07 +02:00 committed by Andi Kleen
parent 7db681d7e4
commit 275f55170e
1 changed files with 40 additions and 72 deletions

View File

@ -30,11 +30,12 @@ wakeup_code:
cld cld
# setup data segment # setup data segment
movw %cs, %ax movw %cs, %ax
movw %ax, %ds # Make ds:0 point to wakeup_start movw %ax, %ds # Make ds:0 point to wakeup_start
movw %ax, %ss movw %ax, %ss
mov $(wakeup_stack - wakeup_code), %sp # Private stack is needed for ASUS board # Private stack is needed for ASUS board
mov $(wakeup_stack - wakeup_code), %sp
pushl $0 # Kill any dangerous flags pushl $0 # Kill any dangerous flags
popfl popfl
movl real_magic - wakeup_code, %eax movl real_magic - wakeup_code, %eax
@ -45,7 +46,7 @@ wakeup_code:
jz 1f jz 1f
lcall $0xc000,$3 lcall $0xc000,$3
movw %cs, %ax movw %cs, %ax
movw %ax, %ds # Bios might have played with that movw %ax, %ds # Bios might have played with that
movw %ax, %ss movw %ax, %ss
1: 1:
@ -75,9 +76,12 @@ wakeup_code:
jmp 1f jmp 1f
1: 1:
.byte 0x66, 0xea # prefix + jmpi-opcode ljmpl *(wakeup_32_vector - wakeup_code)
.long wakeup_32 - __START_KERNEL_map
.word __KERNEL_CS .balign 4
wakeup_32_vector:
.long wakeup_32 - __START_KERNEL_map
.word __KERNEL32_CS, 0
.code32 .code32
wakeup_32: wakeup_32:
@ -96,65 +100,50 @@ wakeup_32:
jnc bogus_cpu jnc bogus_cpu
movl %edx,%edi movl %edx,%edi
movw $__KERNEL_DS, %ax movl $__KERNEL_DS, %eax
movw %ax, %ds movl %eax, %ds
movw %ax, %es
movw %ax, %fs
movw %ax, %gs
movw $__KERNEL_DS, %ax
movw %ax, %ss
mov $(wakeup_stack - __START_KERNEL_map), %esp
movl saved_magic - __START_KERNEL_map, %eax movl saved_magic - __START_KERNEL_map, %eax
cmpl $0x9abcdef0, %eax cmpl $0x9abcdef0, %eax
jne bogus_32_magic jne bogus_32_magic
movw $0x0e00 + 'i', %ds:(0xb8012)
movb $0xa8, %al ; outb %al, $0x80;
/* /*
* Prepare for entering 64bits mode * Prepare for entering 64bits mode
*/ */
/* Enable PAE mode and PGE */ /* Enable PAE */
xorl %eax, %eax xorl %eax, %eax
btsl $5, %eax btsl $5, %eax
btsl $7, %eax
movl %eax, %cr4 movl %eax, %cr4
/* Setup early boot stage 4 level pagetables */ /* Setup early boot stage 4 level pagetables */
movl $(wakeup_level4_pgt - __START_KERNEL_map), %eax movl $(wakeup_level4_pgt - __START_KERNEL_map), %eax
movl %eax, %cr3 movl %eax, %cr3
/* Setup EFER (Extended Feature Enable Register) */
movl $MSR_EFER, %ecx
rdmsr
/* Fool rdmsr and reset %eax to avoid dependences */
xorl %eax, %eax
/* Enable Long Mode */ /* Enable Long Mode */
xorl %eax, %eax
btsl $_EFER_LME, %eax btsl $_EFER_LME, %eax
/* Enable System Call */
btsl $_EFER_SCE, %eax
/* No Execute supported? */ /* No Execute supported? */
btl $20,%edi btl $20,%edi
jnc 1f jnc 1f
btsl $_EFER_NX, %eax btsl $_EFER_NX, %eax
1:
/* Make changes effective */ /* Make changes effective */
1: movl $MSR_EFER, %ecx
xorl %edx, %edx
wrmsr wrmsr
wbinvd
xorl %eax, %eax xorl %eax, %eax
btsl $31, %eax /* Enable paging and in turn activate Long Mode */ btsl $31, %eax /* Enable paging and in turn activate Long Mode */
btsl $0, %eax /* Enable protected mode */ btsl $0, %eax /* Enable protected mode */
btsl $1, %eax /* Enable MP */
btsl $4, %eax /* Enable ET */
btsl $5, %eax /* Enable NE */
btsl $16, %eax /* Enable WP */
btsl $18, %eax /* Enable AM */
/* Make changes effective */ /* Make changes effective */
movl %eax, %cr0 movl %eax, %cr0
/* At this point: /* At this point:
CR4.PAE must be 1 CR4.PAE must be 1
CS.L must be 0 CS.L must be 0
@ -162,11 +151,6 @@ wakeup_32:
Next instruction must be a branch Next instruction must be a branch
This must be on identity-mapped page This must be on identity-mapped page
*/ */
jmp reach_compatibility_mode
reach_compatibility_mode:
movw $0x0e00 + 'i', %ds:(0xb8012)
movb $0xa8, %al ; outb %al, $0x80;
/* /*
* At this point we're in long mode but in 32bit compatibility mode * At this point we're in long mode but in 32bit compatibility mode
* with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn * with EFER.LME = 1, CS.L = 0, CS.D = 1 (and in turn
@ -174,24 +158,19 @@ reach_compatibility_mode:
* the new gdt/idt that has __KERNEL_CS with CS.L = 1. * the new gdt/idt that has __KERNEL_CS with CS.L = 1.
*/ */
movw $0x0e00 + 'n', %ds:(0xb8014)
movb $0xa9, %al ; outb %al, $0x80
/* Load new GDT with the 64bit segment using 32bit descriptor */
movl $(pGDT32 - __START_KERNEL_map), %eax
lgdt (%eax)
movl $(wakeup_jumpvector - __START_KERNEL_map), %eax
/* Finally jump in 64bit mode */ /* Finally jump in 64bit mode */
ljmp *(%eax) ljmp *(wakeup_long64_vector - __START_KERNEL_map)
wakeup_jumpvector: .balign 4
.long wakeup_long64 - __START_KERNEL_map wakeup_long64_vector:
.word __KERNEL_CS .long wakeup_long64 - __START_KERNEL_map
.word __KERNEL_CS, 0
.code64 .code64
/* Hooray, we are in Long 64-bit mode (but still running in low memory) */ /* Hooray, we are in Long 64-bit mode (but still running in
* low memory)
*/
wakeup_long64: wakeup_long64:
/* /*
* We must switch to a new descriptor in kernel space for the GDT * We must switch to a new descriptor in kernel space for the GDT
@ -201,6 +180,9 @@ wakeup_long64:
*/ */
lgdt cpu_gdt_descr - __START_KERNEL_map lgdt cpu_gdt_descr - __START_KERNEL_map
movw $0x0e00 + 'n', %ds:(0xb8014)
movb $0xa9, %al ; outb %al, $0x80
movw $0x0e00 + 'u', %ds:(0xb8016) movw $0x0e00 + 'u', %ds:(0xb8016)
nop nop
@ -227,33 +209,19 @@ wakeup_long64:
.align 64 .align 64
gdta: gdta:
/* Its good to keep gdt in sync with one in trampoline.S */
.word 0, 0, 0, 0 # dummy .word 0, 0, 0, 0 # dummy
/* ??? Why I need the accessed bit set in order for this to work? */
.word 0, 0, 0, 0 # unused .quad 0x00cf9b000000ffff # __KERNEL32_CS
.quad 0x00af9b000000ffff # __KERNEL_CS
.word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb) .quad 0x00cf93000000ffff # __KERNEL_DS
.word 0 # base address = 0
.word 0x9B00 # code read/exec. ??? Why I need 0x9B00 (as opposed to 0x9A00 in order for this to work?)
.word 0x00CF # granularity = 4096, 386
# (+5th nibble of limit)
.word 0xFFFF # 4Gb - (0x100000*0x1000 = 4Gb)
.word 0 # base address = 0
.word 0x9200 # data read/write
.word 0x00CF # granularity = 4096, 386
# (+5th nibble of limit)
# this is 64bit descriptor for code
.word 0xFFFF
.word 0
.word 0x9A00 # code read/exec
.word 0x00AF # as above, but it is long mode and with D=0
idt_48a: idt_48a:
.word 0 # idt limit = 0 .word 0 # idt limit = 0
.word 0, 0 # idt base = 0L .word 0, 0 # idt base = 0L
gdt_48a: gdt_48a:
.word 0x8000 # gdt limit=2048, .word 0x800 # gdt limit=2048,
# 256 GDT entries # 256 GDT entries
.word 0, 0 # gdt base (filled in later) .word 0, 0 # gdt base (filled in later)
@ -263,7 +231,7 @@ video_mode: .quad 0
video_flags: .quad 0 video_flags: .quad 0
bogus_real_magic: bogus_real_magic:
movb $0xba,%al ; outb %al,$0x80 movb $0xba,%al ; outb %al,$0x80
jmp bogus_real_magic jmp bogus_real_magic
bogus_32_magic: bogus_32_magic: