1/*- 2 * Copyright (c) 2001 Takanori Watanabe <takawata@jp.freebsd.org> 3 * Copyright (c) 2001 Mitsuru IWASAKI <iwasaki@jp.freebsd.org> 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30#define LOCORE 31 32#include <machine/specialreg.h> 33 34 .align 4 35 .code16 36wakeup_16: 37 nop 38 cli 39 40 /* Set up segment registers for real mode */ 41 movw %cs,%ax 42 movw %ax,%ds 43 movw %ax,%ss 44 45 /* Load GDT for real mode */ 46 lgdt physical_gdt 47 48 /* Restore CR2, CR3 and CR4 */ 49 mov previous_cr2,%eax 50 mov %eax,%cr2 51 mov previous_cr3,%eax 52 mov %eax,%cr3 53 mov previous_cr4,%eax 54 mov %eax,%cr4 55 56 /* Transfer some values to protected mode */ 57#define NVALUES 9 58#define TRANSFER_STACK32(val, idx) \ 59 mov val,%eax; \ 60 mov %eax,wakeup_32stack+(idx+1)+(idx*4); 61 62 TRANSFER_STACK32(previous_ss, (NVALUES - 9)) 63 TRANSFER_STACK32(previous_fs, (NVALUES - 8)) 64 TRANSFER_STACK32(previous_ds, (NVALUES - 7)) 65 TRANSFER_STACK32(physical_gdt+2, (NVALUES - 6)) 66 TRANSFER_STACK32(where_to_recover, (NVALUES - 5)) 67 TRANSFER_STACK32(previous_idt+2, (NVALUES - 4)) 68 TRANSFER_STACK32(previous_ldt, (NVALUES - 3)) 69 TRANSFER_STACK32(previous_gdt+2, (NVALUES - 2)) 70 TRANSFER_STACK32(previous_tr, (NVALUES - 1)) 71 TRANSFER_STACK32(previous_cr0, (NVALUES - 0)) 72 73 mov physical_esp,%esi /* to be used in 32bit code */ 74 75 /* Enable protected mode */ 76 mov %cr0,%eax 77 orl $(CR0_PE),%eax 78 mov %eax,%cr0 79 80wakeup_sw32: 81 /* Switch to protected mode by intersegmental jump */ 82 ljmpl $0x8,$0x12345678 /* Code location, to be replaced */ 83 84 .code32 85wakeup_32: 86 /* 87 * Switched to protected mode w/o paging 88 * %esi: KERNEL stack pointer (physical address) 89 */ 90 91 nop 92 93 /* Set up segment registers for protected mode */ 94 movw $0x10,%ax /* KDSEL to segment registers */ 95 movw %ax,%ds 96 movw %ax,%es 97 movw %ax,%gs 98 movw %ax,%ss 99 movw $0x18,%ax /* KPSEL to %fs */ 100 movw %ax,%fs 101 movl %esi,%esp /* physical address stack pointer */ 102 103wakeup_32stack: 104 /* Operands are overwritten in 16bit code */ 105 pushl $0xabcdef09 /* ss + dummy */ 106 pushl $0xabcdef08 /* fs + gs */ 107 pushl $0xabcdef07 /* ds + es */ 108 pushl $0xabcdef06 /* gdt:base (physical address) */ 109 pushl $0xabcdef05 /* recover address */ 110 pushl $0xabcdef04 /* idt:base */ 111 pushl $0xabcdef03 /* ldt + idt:limit */ 112 pushl $0xabcdef02 /* gdt:base */ 113 pushl $0xabcdef01 /* TR + gdt:limit */ 114 pushl $0xabcdef00 /* CR0 */ 115 116 movl %esp,%ebp 117#define CR0_REGISTER 0(%ebp) 118#define TASK_REGISTER 4(%ebp) 119#define PREVIOUS_GDT 6(%ebp) 120#define PREVIOUS_LDT 12(%ebp) 121#define PREVIOUS_IDT 14(%ebp) 122#define RECOVER_ADDR 20(%ebp) 123#define PHYSICAL_GDT_BASE 24(%ebp) 124#define PREVIOUS_DS 28(%ebp) 125#define PREVIOUS_ES 30(%ebp) 126#define PREVIOUS_FS 32(%ebp) 127#define PREVIOUS_GS 34(%ebp) 128#define PREVIOUS_SS 36(%ebp) 129 130 /* Fixup TSS type field */ 131#define TSS_TYPEFIX_MASK 0xf9 132 xorl %esi,%esi 133 movl PHYSICAL_GDT_BASE,%ebx 134 movw TASK_REGISTER,%si 135 leal (%ebx,%esi),%eax /* get TSS segment descriptor */ 136 andb $TSS_TYPEFIX_MASK,5(%eax) 137 138 /* Prepare to return to sleep/wakeup code point */ 139 lgdt PREVIOUS_GDT 140 lidt PREVIOUS_IDT 141 142 xorl %eax,%eax 143 movl %eax,%ebx 144 movl %eax,%ecx 145 movl %eax,%edx 146 movl %eax,%esi 147 movl %eax,%edi 148 movl PREVIOUS_DS,%ebx 149 movl PREVIOUS_FS,%ecx 150 movl PREVIOUS_SS,%edx 151 movw TASK_REGISTER,%si 152 shll $16,%esi 153 movw PREVIOUS_LDT,%si 154 movl RECOVER_ADDR,%edi 155 156 /* Enable paging and etc. */ 157 movl CR0_REGISTER,%eax 158 movl %eax,%cr0 159 160 /* Flush the prefetch queue */ 161 jmp 1f 1621: jmp 1f 1631: 164 /* 165 * Now that we are in kernel virtual memory addressing 166 * %ebx: ds + es 167 * %ecx: fs + gs 168 * %edx: ss + dummy 169 * %esi: LDTR + TR 170 * %edi: recover address 171 */ 172 173 nop 174 175 movl %esi,%eax /* LDTR + TR */ 176 lldt %ax /* load LDT register */ 177 shrl $16,%eax 178 ltr %ax /* load task register */ 179 180 /* Restore segment registers */ 181 movl %ebx,%eax /* ds + es */ 182 movw %ax,%ds 183 shrl $16,%eax 184 movw %ax,%es 185 movl %ecx,%eax /* fs + gs */ 186 movw %ax,%fs 187 shrl $16,%eax 188 movw %ax,%gs 189 movl %edx,%eax /* ss */ 190 movw %ax,%ss 191 192 /* Jump to acpi_restorecpu() */ 193 jmp *%edi 194 195/* used in real mode */ 196physical_gdt: .word 0 197 .long 0 198physical_esp: .long 0 199previous_cr2: .long 0 200previous_cr3: .long 0 201previous_cr4: .long 0 202 203/* transfer from real mode to protected mode */ 204previous_cr0: .long 0 205previous_tr: .word 0 206previous_gdt: .word 0 207 .long 0 208previous_ldt: .word 0 209previous_idt: .word 0 210 .long 0 211where_to_recover: .long 0 212previous_ds: .word 0 213previous_es: .word 0 214previous_fs: .word 0 215previous_gs: .word 0 216previous_ss: .word 0 217dummy: .word 0 218 219