From 14fcaff40a0935d50bcd694917237e0cea05134f Mon Sep 17 00:00:00 2001 From: Paul Irofti Date: Wed, 25 Nov 2009 15:41:44 +0000 Subject: 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@. --- sys/arch/amd64/amd64/acpi_wakecode.S | 49 +++++++++++++++++++++++++++++++++++- sys/arch/i386/i386/acpi_wakecode.S | 47 ++++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+), 1 deletion(-) (limited to 'sys/arch') 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 * Copyright (c) 2001 Mitsuru IWASAKI @@ -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 -- cgit v1.2.3