summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorPaul Irofti <pirofti@cvs.openbsd.org>2009-11-25 15:41:44 +0000
committerPaul Irofti <pirofti@cvs.openbsd.org>2009-11-25 15:41:44 +0000
commit14fcaff40a0935d50bcd694917237e0cea05134f (patch)
tree2904fa26257166aac801951200cc6590f49d36a6 /sys/arch
parent64095f70dab18523608e004e32ffd36d7ec57d24 (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.S49
-rw-r--r--sys/arch/i386/i386/acpi_wakecode.S47
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