diff options
author | Paul Irofti <pirofti@cvs.openbsd.org> | 2009-11-25 15:41:44 +0000 |
---|---|---|
committer | Paul Irofti <pirofti@cvs.openbsd.org> | 2009-11-25 15:41:44 +0000 |
commit | 14fcaff40a0935d50bcd694917237e0cea05134f (patch) | |
tree | 2904fa26257166aac801951200cc6590f49d36a6 /sys/arch | |
parent | 64095f70dab18523608e004e32ffd36d7ec57d24 (diff) |
Make sure we get a clean gdt from the BIOS.
Some vendors screw us up on resume giving back a dirty gdt which
prevents us to go into protected mode. This makes sure the gdt is
clean, its the only way to do this and its the only way to be sure
we're clean on resume.
This fixes quite a few laptops that didn't resume but rebooted or did
other screwy things because of a dirty gdt.
Worked with mlarkin@ for quite a few houres last night.
Tested by many on both amd64 and i386.
Okay deraadt@.
Diffstat (limited to 'sys/arch')
-rw-r--r-- | sys/arch/amd64/amd64/acpi_wakecode.S | 49 | ||||
-rw-r--r-- | sys/arch/i386/i386/acpi_wakecode.S | 47 |
2 files changed, 95 insertions, 1 deletions
diff --git a/sys/arch/amd64/amd64/acpi_wakecode.S b/sys/arch/amd64/amd64/acpi_wakecode.S index bd0763d46ab..d1f86ecfa21 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.5 2009/11/24 17:00:01 mlarkin Exp $ */ +/* $OpenBSD: acpi_wakecode.S,v 1.6 2009/11/25 15:41:43 pirofti Exp $ */ /* * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org> * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> @@ -57,6 +57,7 @@ #define _ACPI_TRMP_LABEL(a) a = . - _C_LABEL(acpi_real_mode_resume) + ACPI_TRAMPOLINE #define _ACPI_TRMP_OFFSET(a) a = . - _C_LABEL(acpi_real_mode_resume) +#define _ACPI_RM_SEGMENT (ACPI_TRAMPOLINE >> 4) /* * On wakeup, we'll start executing at acpi_real_mode_resume. @@ -91,6 +92,28 @@ _C_LABEL(acpi_real_mode_resume): cli cld + /* Some BIOS vendors screw up the gdt, make sure we clean it */ + movw $0x10, %cx + lgdtl %cs:clean_gdt + movl %cr0, %eax + orb $(CR0_PE), %al + movl %eax, %cr0 + jmp 1f +1: ljmpw $0x8, $clean1 + +_ACPI_TRMP_OFFSET(clean1) + movw %cx, %ds + movw %cx, %es + movw %cx, %ss + movw %cx, %fs + movw %cx, %gs + + andb $~(CR0_PE), %al + movl %eax, %cr0 + ljmpw $_ACPI_RM_SEGMENT , $clean2 + +_ACPI_TRMP_OFFSET(clean2) + /* * Set up segment registers for real mode. * We'll only be in real mode for a moment, and we don't have @@ -99,7 +122,9 @@ _C_LABEL(acpi_real_mode_resume): */ movw %cs,%ax movw %ax,%ds + movw %ax,%es movw %ax,%ss + lidtl clean_idt /* * Set up stack to grow down from offset 0x0FFE. @@ -419,6 +444,28 @@ _ACPI_TRMP_LABEL(tmp_gdtable) .byte 0, 0x93, 0xcf, 0 _ACPI_TRMP_LABEL(tmp_gdt_end) + .align 8, 0 +_ACPI_TRMP_OFFSET(clean_idt) + .word 0xffff + .long 0 + .word 0 + +_ACPI_TRMP_OFFSET(clean_gdt) + .word clean_gdt_end - clean_gdtable + .long clean_gdtable + + .align 8, 0 +_ACPI_TRMP_LABEL(clean_gdtable) + .word 0, 0 + .byte 0, 0, 0, 0 + + .word 0xffff, ACPI_TRAMPOLINE + .byte 0, 0x9b, 0, 0 + + .word 0xffff, ACPI_TRAMPOLINE + .byte 0, 0x93, 0, 0 +_ACPI_TRMP_LABEL(clean_gdt_end) + .align 8 _ACPI_TRMP_LABEL(tmp_gdt64) .word tmp_gdt64_end - tmp_gdtable64 diff --git a/sys/arch/i386/i386/acpi_wakecode.S b/sys/arch/i386/i386/acpi_wakecode.S index 3f80542bf8a..04c6c52b598 100644 --- a/sys/arch/i386/i386/acpi_wakecode.S +++ b/sys/arch/i386/i386/acpi_wakecode.S @@ -56,6 +56,7 @@ #define _ACPI_TRMP_LABEL(a) a = . - _C_LABEL(acpi_real_mode_resume) + ACPI_TRAMPOLINE #define _ACPI_TRMP_OFFSET(a) a = . - _C_LABEL(acpi_real_mode_resume) +#define _ACPI_RM_SEGMENT (ACPI_TRAMPOLINE >> 4) /* * On wakeup, we'll start executing at acpi_real_mode_resume. @@ -87,6 +88,28 @@ _C_LABEL(acpi_real_mode_resume): cli cld + /* Some BIOS vendors screw up the gdt, make sure we clean it */ + movw $0x10, %cx + lgdtl %cs:clean_gdt + movl %cr0, %eax + orb $(CR0_PE), %al + movl %eax, %cr0 + jmp 1f +1: ljmpw $0x8, $clean1 + +_ACPI_TRMP_OFFSET(clean1) + movw %cx, %ds + movw %cx, %es + movw %cx, %ss + movw %cx, %fs + movw %cx, %gs + + andb $~(CR0_PE), %al + movl %eax, %cr0 + ljmpw $_ACPI_RM_SEGMENT , $clean2 + +_ACPI_TRMP_OFFSET(clean2) + /* * Set up segment registers for real mode. * We'll only be in real mode for a moment, and we don't have @@ -95,7 +118,9 @@ _C_LABEL(acpi_real_mode_resume): */ movw %cs,%ax movw %ax,%ds + movw %ax,%es movw %ax,%ss + lidtl clean_idt /* * Set up stack to grow down from offset 0x0FFE. @@ -362,6 +387,28 @@ _ACPI_TRMP_LABEL(tmp_gdtable) .byte 0, 0x93, 0xcf, 0 _ACPI_TRMP_LABEL(tmp_gdt_end) + .align 8, 0 +_ACPI_TRMP_OFFSET(clean_idt) + .word 0xffff + .long 0 + .word 0 + +_ACPI_TRMP_OFFSET(clean_gdt) + .word clean_gdt_end - clean_gdtable + .long clean_gdtable + + .align 8, 0 +_ACPI_TRMP_LABEL(clean_gdtable) + .word 0, 0 + .byte 0, 0, 0, 0 + + .word 0xffff, ACPI_TRAMPOLINE + .byte 0, 0x9b, 0, 0 + + .word 0xffff, ACPI_TRAMPOLINE + .byte 0, 0x93, 0, 0 +_ACPI_TRMP_LABEL(clean_gdt_end) + .align 4 _ACPI_TRMP_LABEL(acpi_saved_ebx) .long 0 |