mirror of https://gitee.com/openkylin/linux.git
[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:
parent
7db681d7e4
commit
275f55170e
|
@ -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:
|
||||||
|
|
Loading…
Reference in New Issue