acpi_wakecode.S revision 121830
180028Stakawata/*- 280028Stakawata * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org> 380028Stakawata * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 480028Stakawata * All rights reserved. 580028Stakawata * 680028Stakawata * Redistribution and use in source and binary forms, with or without 780028Stakawata * modification, are permitted provided that the following conditions 880028Stakawata * are met: 980028Stakawata * 1. Redistributions of source code must retain the above copyright 1080028Stakawata * notice, this list of conditions and the following disclaimer. 1180028Stakawata * 2. Redistributions in binary form must reproduce the above copyright 1280028Stakawata * notice, this list of conditions and the following disclaimer in the 1380028Stakawata * documentation and/or other materials provided with the distribution. 1480028Stakawata * 1580028Stakawata * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1680028Stakawata * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1780028Stakawata * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1880028Stakawata * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1980028Stakawata * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2080028Stakawata * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2180028Stakawata * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2280028Stakawata * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2380028Stakawata * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2480028Stakawata * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2580028Stakawata * SUCH DAMAGE. 2680028Stakawata */ 2780028Stakawata 28115681Sobrien#include <machine/asm.h> 29115681Sobrien__FBSDID("$FreeBSD: head/sys/i386/acpica/acpi_wakecode.S 121830 2003-11-01 00:18:29Z njl $"); 30115681Sobrien 3180028Stakawata#define LOCORE 3280028Stakawata 33121830Snjl#include <machine/param.h> 3480028Stakawata#include <machine/specialreg.h> 3580028Stakawata 3680028Stakawata .align 4 3780028Stakawata .code16 3880028Stakawatawakeup_16: 3980028Stakawata nop 4080028Stakawata cli 4180028Stakawata 42121830Snjl /* 43121830Snjl * Set up segment registers for real mode and a small stack for 44121830Snjl * any calls we make. 45121830Snjl */ 4680028Stakawata movw %cs,%ax 4780028Stakawata movw %ax,%ds 4880028Stakawata movw %ax,%ss 49121830Snjl movw $PAGE_SIZE,%sp 50121830Snjl 51121830Snjl /* Re-initialize video BIOS if the reset_video tunable is set. */ 52121830Snjl cmp $1,reset_video 53121830Snjl je wakeup_16_gdt 54121830Snjl lcall $0xc000,$3 55121830Snjl 56121603Snjl /* 57121830Snjl * Set up segment registers for real mode again in case the 58121830Snjl * previous BIOS call clobbers them. 59121603Snjl */ 60121830Snjl movw %cs,%ax 61121830Snjl movw %ax,%ds 62121830Snjl movw %ax,%ss 6380028Stakawata 64121743Siwasakiwakeup_16_gdt: 6580028Stakawata /* Load GDT for real mode */ 6680028Stakawata lgdt physical_gdt 6780028Stakawata 6880028Stakawata /* Restore CR2, CR3 and CR4 */ 6980028Stakawata mov previous_cr2,%eax 7080028Stakawata mov %eax,%cr2 7180028Stakawata mov previous_cr3,%eax 7280028Stakawata mov %eax,%cr3 7380028Stakawata mov previous_cr4,%eax 7480028Stakawata mov %eax,%cr4 7580028Stakawata 7680028Stakawata /* Transfer some values to protected mode */ 7780028Stakawata#define NVALUES 9 7880028Stakawata#define TRANSFER_STACK32(val, idx) \ 7980028Stakawata mov val,%eax; \ 8080028Stakawata mov %eax,wakeup_32stack+(idx+1)+(idx*4); 8180028Stakawata 8280028Stakawata TRANSFER_STACK32(previous_ss, (NVALUES - 9)) 8380028Stakawata TRANSFER_STACK32(previous_fs, (NVALUES - 8)) 8480028Stakawata TRANSFER_STACK32(previous_ds, (NVALUES - 7)) 8580028Stakawata TRANSFER_STACK32(physical_gdt+2, (NVALUES - 6)) 8680028Stakawata TRANSFER_STACK32(where_to_recover, (NVALUES - 5)) 8780028Stakawata TRANSFER_STACK32(previous_idt+2, (NVALUES - 4)) 8880028Stakawata TRANSFER_STACK32(previous_ldt, (NVALUES - 3)) 8980028Stakawata TRANSFER_STACK32(previous_gdt+2, (NVALUES - 2)) 9080028Stakawata TRANSFER_STACK32(previous_tr, (NVALUES - 1)) 9180028Stakawata TRANSFER_STACK32(previous_cr0, (NVALUES - 0)) 9280028Stakawata 9380028Stakawata mov physical_esp,%esi /* to be used in 32bit code */ 9480028Stakawata 9580028Stakawata /* Enable protected mode */ 9680028Stakawata mov %cr0,%eax 9780028Stakawata orl $(CR0_PE),%eax 9880028Stakawata mov %eax,%cr0 9980028Stakawata 10080028Stakawatawakeup_sw32: 10180028Stakawata /* Switch to protected mode by intersegmental jump */ 10280028Stakawata ljmpl $0x8,$0x12345678 /* Code location, to be replaced */ 10380028Stakawata 10480028Stakawata .code32 10580028Stakawatawakeup_32: 10680028Stakawata /* 10780028Stakawata * Switched to protected mode w/o paging 10880028Stakawata * %esi: KERNEL stack pointer (physical address) 10980028Stakawata */ 11080028Stakawata 11180028Stakawata nop 11280028Stakawata 11380028Stakawata /* Set up segment registers for protected mode */ 11480028Stakawata movw $0x10,%ax /* KDSEL to segment registers */ 11580028Stakawata movw %ax,%ds 11680028Stakawata movw %ax,%es 11780028Stakawata movw %ax,%gs 11880028Stakawata movw %ax,%ss 11980028Stakawata movw $0x18,%ax /* KPSEL to %fs */ 12080028Stakawata movw %ax,%fs 12180028Stakawata movl %esi,%esp /* physical address stack pointer */ 12280028Stakawata 12380028Stakawatawakeup_32stack: 12480028Stakawata /* Operands are overwritten in 16bit code */ 12580028Stakawata pushl $0xabcdef09 /* ss + dummy */ 12680028Stakawata pushl $0xabcdef08 /* fs + gs */ 12780028Stakawata pushl $0xabcdef07 /* ds + es */ 12880028Stakawata pushl $0xabcdef06 /* gdt:base (physical address) */ 12980028Stakawata pushl $0xabcdef05 /* recover address */ 13080028Stakawata pushl $0xabcdef04 /* idt:base */ 13180028Stakawata pushl $0xabcdef03 /* ldt + idt:limit */ 13280028Stakawata pushl $0xabcdef02 /* gdt:base */ 13380028Stakawata pushl $0xabcdef01 /* TR + gdt:limit */ 13480028Stakawata pushl $0xabcdef00 /* CR0 */ 13580028Stakawata 13680028Stakawata movl %esp,%ebp 13780028Stakawata#define CR0_REGISTER 0(%ebp) 13880028Stakawata#define TASK_REGISTER 4(%ebp) 13980028Stakawata#define PREVIOUS_GDT 6(%ebp) 14080028Stakawata#define PREVIOUS_LDT 12(%ebp) 14180028Stakawata#define PREVIOUS_IDT 14(%ebp) 14280028Stakawata#define RECOVER_ADDR 20(%ebp) 14380028Stakawata#define PHYSICAL_GDT_BASE 24(%ebp) 14480028Stakawata#define PREVIOUS_DS 28(%ebp) 14580028Stakawata#define PREVIOUS_ES 30(%ebp) 14680028Stakawata#define PREVIOUS_FS 32(%ebp) 14780028Stakawata#define PREVIOUS_GS 34(%ebp) 14880028Stakawata#define PREVIOUS_SS 36(%ebp) 14980028Stakawata 15080028Stakawata /* Fixup TSS type field */ 15180028Stakawata#define TSS_TYPEFIX_MASK 0xf9 15280028Stakawata xorl %esi,%esi 15380028Stakawata movl PHYSICAL_GDT_BASE,%ebx 15480028Stakawata movw TASK_REGISTER,%si 15580028Stakawata leal (%ebx,%esi),%eax /* get TSS segment descriptor */ 15680028Stakawata andb $TSS_TYPEFIX_MASK,5(%eax) 15780028Stakawata 15880028Stakawata /* Prepare to return to sleep/wakeup code point */ 15980028Stakawata lgdt PREVIOUS_GDT 16080028Stakawata lidt PREVIOUS_IDT 16180028Stakawata 16280028Stakawata xorl %eax,%eax 16380028Stakawata movl %eax,%ebx 16480028Stakawata movl %eax,%ecx 16580028Stakawata movl %eax,%edx 16680028Stakawata movl %eax,%esi 16780028Stakawata movl %eax,%edi 16880028Stakawata movl PREVIOUS_DS,%ebx 16980028Stakawata movl PREVIOUS_FS,%ecx 17080028Stakawata movl PREVIOUS_SS,%edx 17180028Stakawata movw TASK_REGISTER,%si 17280028Stakawata shll $16,%esi 17380028Stakawata movw PREVIOUS_LDT,%si 17480028Stakawata movl RECOVER_ADDR,%edi 17580028Stakawata 17680028Stakawata /* Enable paging and etc. */ 17780028Stakawata movl CR0_REGISTER,%eax 17880028Stakawata movl %eax,%cr0 17980028Stakawata 18080028Stakawata /* Flush the prefetch queue */ 18180028Stakawata jmp 1f 18280028Stakawata1: jmp 1f 18380028Stakawata1: 18480028Stakawata /* 18580028Stakawata * Now that we are in kernel virtual memory addressing 18680028Stakawata * %ebx: ds + es 18780028Stakawata * %ecx: fs + gs 18880028Stakawata * %edx: ss + dummy 18980028Stakawata * %esi: LDTR + TR 19080028Stakawata * %edi: recover address 19180028Stakawata */ 19280028Stakawata 19380028Stakawata nop 19480028Stakawata 19580028Stakawata movl %esi,%eax /* LDTR + TR */ 19680028Stakawata lldt %ax /* load LDT register */ 19780028Stakawata shrl $16,%eax 19880028Stakawata ltr %ax /* load task register */ 19980028Stakawata 20080028Stakawata /* Restore segment registers */ 20180028Stakawata movl %ebx,%eax /* ds + es */ 20280028Stakawata movw %ax,%ds 20380028Stakawata shrl $16,%eax 20480028Stakawata movw %ax,%es 20580028Stakawata movl %ecx,%eax /* fs + gs */ 20680028Stakawata movw %ax,%fs 20780028Stakawata shrl $16,%eax 20880028Stakawata movw %ax,%gs 20980028Stakawata movl %edx,%eax /* ss */ 21080028Stakawata movw %ax,%ss 21180028Stakawata 21280028Stakawata /* Jump to acpi_restorecpu() */ 21380028Stakawata jmp *%edi 21480028Stakawata 21580028Stakawata/* used in real mode */ 21680028Stakawataphysical_gdt: .word 0 21780028Stakawata .long 0 21880028Stakawataphysical_esp: .long 0 21980028Stakawataprevious_cr2: .long 0 22080028Stakawataprevious_cr3: .long 0 22180028Stakawataprevious_cr4: .long 0 222121830Snjlreset_video: .long 0 22380028Stakawata 22480028Stakawata/* transfer from real mode to protected mode */ 22580028Stakawataprevious_cr0: .long 0 22680028Stakawataprevious_tr: .word 0 22780028Stakawataprevious_gdt: .word 0 22880028Stakawata .long 0 22980028Stakawataprevious_ldt: .word 0 23080028Stakawataprevious_idt: .word 0 23180028Stakawata .long 0 23280028Stakawatawhere_to_recover: .long 0 23380028Stakawataprevious_ds: .word 0 23480028Stakawataprevious_es: .word 0 23580028Stakawataprevious_fs: .word 0 23680028Stakawataprevious_gs: .word 0 23780028Stakawataprevious_ss: .word 0 23880028Stakawatadummy: .word 0 239