15db2f26eSSascha Wildner/*- 25db2f26eSSascha Wildner * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org> 35db2f26eSSascha Wildner * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 45db2f26eSSascha Wildner * All rights reserved. 55db2f26eSSascha Wildner * 65db2f26eSSascha Wildner * Redistribution and use in source and binary forms, with or without 75db2f26eSSascha Wildner * modification, are permitted provided that the following conditions 85db2f26eSSascha Wildner * are met: 95db2f26eSSascha Wildner * 1. Redistributions of source code must retain the above copyright 105db2f26eSSascha Wildner * notice, this list of conditions and the following disclaimer. 115db2f26eSSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright 125db2f26eSSascha Wildner * notice, this list of conditions and the following disclaimer in the 135db2f26eSSascha Wildner * documentation and/or other materials provided with the distribution. 145db2f26eSSascha Wildner * 155db2f26eSSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 165db2f26eSSascha Wildner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 175db2f26eSSascha Wildner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 185db2f26eSSascha Wildner * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 195db2f26eSSascha Wildner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 205db2f26eSSascha Wildner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 215db2f26eSSascha Wildner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 225db2f26eSSascha Wildner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 235db2f26eSSascha Wildner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 245db2f26eSSascha Wildner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 255db2f26eSSascha Wildner * SUCH DAMAGE. 265db2f26eSSascha Wildner * 275db2f26eSSascha Wildner * $FreeBSD: src/sys/i386/acpica/acpi_wakecode.S,v 1.9 2004/01/01 22:57:22 njl Exp $ 285db2f26eSSascha Wildner */ 295db2f26eSSascha Wildner 305db2f26eSSascha Wildner#define LOCORE 315db2f26eSSascha Wildner 325db2f26eSSascha Wildner#include <machine/asmacros.h> 335db2f26eSSascha Wildner#include <machine/param.h> 345db2f26eSSascha Wildner#include <machine/specialreg.h> 355db2f26eSSascha Wildner 365db2f26eSSascha Wildner .align 4 375db2f26eSSascha Wildner .code16 385db2f26eSSascha Wildnerwakeup_16: 395db2f26eSSascha Wildner nop 405db2f26eSSascha Wildner cli 415db2f26eSSascha Wildner 425db2f26eSSascha Wildner /* 435db2f26eSSascha Wildner * Set up segment registers for real mode and a small stack for 445db2f26eSSascha Wildner * any calls we make. 455db2f26eSSascha Wildner */ 465db2f26eSSascha Wildner movw %cs,%ax 475db2f26eSSascha Wildner movw %ax,%ds 485db2f26eSSascha Wildner movw %ax,%ss 495db2f26eSSascha Wildner movw $PAGE_SIZE,%sp 505db2f26eSSascha Wildner 515db2f26eSSascha Wildner /* Re-initialize video BIOS if the reset_video tunable is set. */ 52*0993d469SJohn Marino cmpw $0,reset_video 535db2f26eSSascha Wildner je wakeup_16_gdt 545db2f26eSSascha Wildner lcall $0xc000,$3 555db2f26eSSascha Wildner 565db2f26eSSascha Wildner /* 575db2f26eSSascha Wildner * Set up segment registers for real mode again in case the 585db2f26eSSascha Wildner * previous BIOS call clobbers them. 595db2f26eSSascha Wildner */ 605db2f26eSSascha Wildner movw %cs,%ax 615db2f26eSSascha Wildner movw %ax,%ds 625db2f26eSSascha Wildner movw %ax,%ss 635db2f26eSSascha Wildner 645db2f26eSSascha Wildnerwakeup_16_gdt: 655db2f26eSSascha Wildner /* Load GDT for real mode */ 665db2f26eSSascha Wildner lgdt physical_gdt 675db2f26eSSascha Wildner 685db2f26eSSascha Wildner /* Restore CR2, CR3 and CR4 */ 695db2f26eSSascha Wildner mov previous_cr2,%eax 705db2f26eSSascha Wildner mov %eax,%cr2 715db2f26eSSascha Wildner mov previous_cr3,%eax 725db2f26eSSascha Wildner mov %eax,%cr3 735db2f26eSSascha Wildner mov previous_cr4,%eax 745db2f26eSSascha Wildner mov %eax,%cr4 755db2f26eSSascha Wildner 765db2f26eSSascha Wildner /* Transfer some values to protected mode */ 775db2f26eSSascha Wildner#define NVALUES 9 785db2f26eSSascha Wildner#define TRANSFER_STACK32(val, idx) \ 795db2f26eSSascha Wildner mov val,%eax; \ 805db2f26eSSascha Wildner mov %eax,wakeup_32stack+(idx+1)+(idx*4); 815db2f26eSSascha Wildner 825db2f26eSSascha Wildner TRANSFER_STACK32(previous_ss, (NVALUES - 9)) 835db2f26eSSascha Wildner TRANSFER_STACK32(previous_fs, (NVALUES - 8)) 845db2f26eSSascha Wildner TRANSFER_STACK32(previous_ds, (NVALUES - 7)) 855db2f26eSSascha Wildner TRANSFER_STACK32(physical_gdt+2, (NVALUES - 6)) 865db2f26eSSascha Wildner TRANSFER_STACK32(where_to_recover, (NVALUES - 5)) 875db2f26eSSascha Wildner TRANSFER_STACK32(previous_idt+2, (NVALUES - 4)) 885db2f26eSSascha Wildner TRANSFER_STACK32(previous_ldt, (NVALUES - 3)) 895db2f26eSSascha Wildner TRANSFER_STACK32(previous_gdt+2, (NVALUES - 2)) 905db2f26eSSascha Wildner TRANSFER_STACK32(previous_tr, (NVALUES - 1)) 915db2f26eSSascha Wildner TRANSFER_STACK32(previous_cr0, (NVALUES - 0)) 925db2f26eSSascha Wildner 935db2f26eSSascha Wildner mov physical_esp,%esi /* to be used in 32bit code */ 945db2f26eSSascha Wildner 955db2f26eSSascha Wildner /* Enable protected mode */ 965db2f26eSSascha Wildner mov %cr0,%eax 975db2f26eSSascha Wildner orl $(CR0_PE),%eax 985db2f26eSSascha Wildner mov %eax,%cr0 995db2f26eSSascha Wildner 1005db2f26eSSascha Wildnerwakeup_sw32: 1015db2f26eSSascha Wildner /* Switch to protected mode by intersegmental jump */ 1025db2f26eSSascha Wildner ljmpl $0x8,$0x12345678 /* Code location, to be replaced */ 1035db2f26eSSascha Wildner 1045db2f26eSSascha Wildner .code32 1055db2f26eSSascha Wildnerwakeup_32: 1065db2f26eSSascha Wildner /* 1075db2f26eSSascha Wildner * Switched to protected mode w/o paging 1085db2f26eSSascha Wildner * %esi: KERNEL stack pointer (physical address) 1095db2f26eSSascha Wildner */ 1105db2f26eSSascha Wildner 1115db2f26eSSascha Wildner nop 1125db2f26eSSascha Wildner 1135db2f26eSSascha Wildner /* Set up segment registers for protected mode */ 1145db2f26eSSascha Wildner movw $0x10,%ax /* KDSEL to segment registers */ 1155db2f26eSSascha Wildner movw %ax,%ds 1165db2f26eSSascha Wildner movw %ax,%es 1175db2f26eSSascha Wildner movw %ax,%gs 1185db2f26eSSascha Wildner movw %ax,%ss 1195db2f26eSSascha Wildner movw $0x18,%ax /* KPSEL to %fs */ 1205db2f26eSSascha Wildner movw %ax,%fs 1215db2f26eSSascha Wildner movl %esi,%esp /* physical address stack pointer */ 1225db2f26eSSascha Wildner 1235db2f26eSSascha Wildnerwakeup_32stack: 1245db2f26eSSascha Wildner /* Operands are overwritten in 16bit code */ 1255db2f26eSSascha Wildner pushl $0xabcdef09 /* ss + dummy */ 1265db2f26eSSascha Wildner pushl $0xabcdef08 /* fs + gs */ 1275db2f26eSSascha Wildner pushl $0xabcdef07 /* ds + es */ 1285db2f26eSSascha Wildner pushl $0xabcdef06 /* gdt:base (physical address) */ 1295db2f26eSSascha Wildner pushl $0xabcdef05 /* recover address */ 1305db2f26eSSascha Wildner pushl $0xabcdef04 /* idt:base */ 1315db2f26eSSascha Wildner pushl $0xabcdef03 /* ldt + idt:limit */ 1325db2f26eSSascha Wildner pushl $0xabcdef02 /* gdt:base */ 1335db2f26eSSascha Wildner pushl $0xabcdef01 /* TR + gdt:limit */ 1345db2f26eSSascha Wildner pushl $0xabcdef00 /* CR0 */ 1355db2f26eSSascha Wildner 1365db2f26eSSascha Wildner movl %esp,%ebp 1375db2f26eSSascha Wildner#define CR0_REGISTER 0(%ebp) 1385db2f26eSSascha Wildner#define TASK_REGISTER 4(%ebp) 1395db2f26eSSascha Wildner#define PREVIOUS_GDT 6(%ebp) 1405db2f26eSSascha Wildner#define PREVIOUS_LDT 12(%ebp) 1415db2f26eSSascha Wildner#define PREVIOUS_IDT 14(%ebp) 1425db2f26eSSascha Wildner#define RECOVER_ADDR 20(%ebp) 1435db2f26eSSascha Wildner#define PHYSICAL_GDT_BASE 24(%ebp) 1445db2f26eSSascha Wildner#define PREVIOUS_DS 28(%ebp) 1455db2f26eSSascha Wildner#define PREVIOUS_ES 30(%ebp) 1465db2f26eSSascha Wildner#define PREVIOUS_FS 32(%ebp) 1475db2f26eSSascha Wildner#define PREVIOUS_GS 34(%ebp) 1485db2f26eSSascha Wildner#define PREVIOUS_SS 36(%ebp) 1495db2f26eSSascha Wildner 1505db2f26eSSascha Wildner /* Fixup TSS type field */ 1515db2f26eSSascha Wildner#define TSS_TYPEFIX_MASK 0xf9 1525db2f26eSSascha Wildner xorl %esi,%esi 1535db2f26eSSascha Wildner movl PHYSICAL_GDT_BASE,%ebx 1545db2f26eSSascha Wildner movw TASK_REGISTER,%si 1555db2f26eSSascha Wildner leal (%ebx,%esi),%eax /* get TSS segment descriptor */ 1565db2f26eSSascha Wildner andb $TSS_TYPEFIX_MASK,5(%eax) 1575db2f26eSSascha Wildner 1585db2f26eSSascha Wildner /* Prepare to return to sleep/wakeup code point */ 1595db2f26eSSascha Wildner lgdt PREVIOUS_GDT 1605db2f26eSSascha Wildner lidt PREVIOUS_IDT 1615db2f26eSSascha Wildner 1625db2f26eSSascha Wildner xorl %eax,%eax 1635db2f26eSSascha Wildner movl %eax,%ebx 1645db2f26eSSascha Wildner movl %eax,%ecx 1655db2f26eSSascha Wildner movl %eax,%edx 1665db2f26eSSascha Wildner movl %eax,%esi 1675db2f26eSSascha Wildner movl %eax,%edi 1685db2f26eSSascha Wildner movl PREVIOUS_DS,%ebx 1695db2f26eSSascha Wildner movl PREVIOUS_FS,%ecx 1705db2f26eSSascha Wildner movl PREVIOUS_SS,%edx 1715db2f26eSSascha Wildner movw TASK_REGISTER,%si 1725db2f26eSSascha Wildner shll $16,%esi 1735db2f26eSSascha Wildner movw PREVIOUS_LDT,%si 1745db2f26eSSascha Wildner movl RECOVER_ADDR,%edi 1755db2f26eSSascha Wildner 1765db2f26eSSascha Wildner /* Enable paging and etc. */ 1775db2f26eSSascha Wildner movl CR0_REGISTER,%eax 1785db2f26eSSascha Wildner movl %eax,%cr0 1795db2f26eSSascha Wildner 1805db2f26eSSascha Wildner /* Flush the prefetch queue */ 1815db2f26eSSascha Wildner jmp 1f 1825db2f26eSSascha Wildner1: jmp 1f 1835db2f26eSSascha Wildner1: 1845db2f26eSSascha Wildner /* 1855db2f26eSSascha Wildner * Now that we are in kernel virtual memory addressing 1865db2f26eSSascha Wildner * %ebx: ds + es 1875db2f26eSSascha Wildner * %ecx: fs + gs 1885db2f26eSSascha Wildner * %edx: ss + dummy 1895db2f26eSSascha Wildner * %esi: LDTR + TR 1905db2f26eSSascha Wildner * %edi: recover address 1915db2f26eSSascha Wildner */ 1925db2f26eSSascha Wildner 1935db2f26eSSascha Wildner nop 1945db2f26eSSascha Wildner 1955db2f26eSSascha Wildner movl %esi,%eax /* LDTR + TR */ 1965db2f26eSSascha Wildner lldt %ax /* load LDT register */ 1975db2f26eSSascha Wildner shrl $16,%eax 1985db2f26eSSascha Wildner ltr %ax /* load task register */ 1995db2f26eSSascha Wildner 2005db2f26eSSascha Wildner /* Restore segment registers */ 2015db2f26eSSascha Wildner movl %ebx,%eax /* ds + es */ 2025db2f26eSSascha Wildner movw %ax,%ds 2035db2f26eSSascha Wildner shrl $16,%eax 2045db2f26eSSascha Wildner movw %ax,%es 2055db2f26eSSascha Wildner movl %ecx,%eax /* fs + gs */ 2065db2f26eSSascha Wildner movw %ax,%fs 2075db2f26eSSascha Wildner shrl $16,%eax 2085db2f26eSSascha Wildner movw %ax,%gs 2095db2f26eSSascha Wildner movl %edx,%eax /* ss */ 2105db2f26eSSascha Wildner movw %ax,%ss 2115db2f26eSSascha Wildner 2125db2f26eSSascha Wildner /* Jump to acpi_restorecpu() */ 2135db2f26eSSascha Wildner jmp *%edi 2145db2f26eSSascha Wildner 2155db2f26eSSascha Wildner/* used in real mode */ 2165db2f26eSSascha Wildnerphysical_gdt: .word 0 2175db2f26eSSascha Wildner .long 0 2185db2f26eSSascha Wildnerphysical_esp: .long 0 2195db2f26eSSascha Wildnerprevious_cr2: .long 0 2205db2f26eSSascha Wildnerprevious_cr3: .long 0 2215db2f26eSSascha Wildnerprevious_cr4: .long 0 2225db2f26eSSascha Wildnerreset_video: .long 0 2235db2f26eSSascha Wildner 2245db2f26eSSascha Wildner/* transfer from real mode to protected mode */ 2255db2f26eSSascha Wildnerprevious_cr0: .long 0 2265db2f26eSSascha Wildnerprevious_tr: .word 0 2275db2f26eSSascha Wildnerprevious_gdt: .word 0 2285db2f26eSSascha Wildner .long 0 2295db2f26eSSascha Wildnerprevious_ldt: .word 0 2305db2f26eSSascha Wildnerprevious_idt: .word 0 2315db2f26eSSascha Wildner .long 0 2325db2f26eSSascha Wildnerwhere_to_recover: .long 0 2335db2f26eSSascha Wildnerprevious_ds: .word 0 2345db2f26eSSascha Wildnerprevious_es: .word 0 2355db2f26eSSascha Wildnerprevious_fs: .word 0 2365db2f26eSSascha Wildnerprevious_gs: .word 0 2375db2f26eSSascha Wildnerprevious_ss: .word 0 2385db2f26eSSascha Wildnerdummy: .word 0 239