1/* $NetBSD: realprot.S,v 1.3 2004/02/13 11:36:14 wiz Exp $ */ 2 3/*- 4 * Copyright (c) 2003 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by David Laight. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39/* 40 * Loosely based on code from stand/lib/libcrt/bootsect/start_bootsect.S 41 */ 42 43#include <machine/asm.h> 44 45#define CR0_PE 1 46 47 .text 48 .align 16 49gdt: 50 .word 0, 0 51 .byte 0, 0x00, 0x00, 0 52 53 /* kernel code segment */ 54 .globl flatcodeseg 55flatcodeseg = . - gdt 56 .word 0xffff, 0 57 .byte 0, 0x9f, 0xcf, 0 58 59 /* kernel data segment */ 60 .globl flatdataseg 61flatdataseg = . - gdt 62 .word 0xffff, 0 63 .byte 0, 0x93, 0xcf, 0 64 65 /* boot code segment, base will be patched */ 66bootcodeseg = . - gdt 67 .word 0xffff, 0 68 .byte 0, 0x9e, 0x4f, 0 69 70 /* boot data segment, base will be patched */ 71bootdataseg = . - gdt 72 .word 0xffff, 0 73 .byte 0, 0x92, 0x4f, 0 74 75 /* 16 bit real mode, base will be patched */ 76bootrealseg = . - gdt 77 .word 0xffff, 0 78 .byte 0, 0x9e, 0x00, 0 79 80 /* limits (etc) for data segment in real mode */ 81bootrealdata = . - gdt 82 .word 0xffff, 0 83 .byte 0, 0x92, 0x00, 0 84gdtlen = . - gdt 85 86 .align 16 87gdtarg: 88 .word gdtlen-1 /* limit */ 89 .long 0 /* physical addr, will be inserted */ 90 91toreal: .word xreal /* off:seg address for indirect jump */ 92ourseg: .word 0 /* real mode code and data segment */ 93 94stkseg: .word 0 /* real mode stack segment */ 95stkdif: .long 0 /* diff. between real and prot sp */ 96 97 .global gdt_fixup 98gdt_fixup: 99 .code16 100 push %ax 101 push %dx 102 103 xorl %eax, %eax 104 mov %cs, %ax 105 mov %ax, ourseg 106 /* sort out stuff for %ss != %ds */ 107 movw %ss, %dx 108 movw %dx, stkseg 109 subw %ax, %dx 110 shll $16, %edx 111 shrl $12, %edx 112 movl %edx, stkdif 113 114 /* fix up GDT entries for bootstrap */ 115 mov %ax, %dx 116 shll $4, %eax 117 shr $12, %dx 118 119#define FIXUP(gdt_index) \ 120 movw %ax, gdt+gdt_index+2; \ 121 movb %dl, gdt+gdt_index+4 122 123 FIXUP(bootcodeseg) 124 FIXUP(bootrealseg) 125 FIXUP(bootdataseg) 126 127 /* fix up GDT pointer */ 128 addl $gdt, %eax 129 movl %eax, gdtarg+2 130 131 pop %dx 132 pop %ax 133 ret 134 135/* 136 * real_to_prot() 137 * 138 * Switch CPU to 32bit protected mode to execute C. 139 * 140 * NB: Call with the 32bit calll instruction so that a 32 bit 141 * return address is pushed. 142 * 143 * All registers are preserved, %ss:%esp will point to the same 144 * place as %ss:%sp did, although the actual value of %esp might 145 * be changed. 146 * 147 * Interrupts are disabled while we are in 32bit mode to save us 148 * having to setup a different IDT. This code is only used during 149 * the boot process and it doesn't use any interrupts. 150 */ 151ENTRY(real_to_prot) 152 .code16 153 pushl %eax 154 cli 155 156 lgdt %cs:gdtarg /* Global descriptor table */ 157 158 movl %cr0, %eax 159 or $CR0_PE, %ax 160 movl %eax, %cr0 /* Enter 'protected mode' */ 161 162 ljmp $bootcodeseg, $1f /* Jump into a 32bit segment */ 1631: 164 165 .code32 166 /* Set all the segment registers to map the same area as the code */ 167 mov $bootdataseg, %eax 168 mov %ax, %ds 169 mov %ax, %es 170 mov %ax, %ss 171 addl stkdif, %esp /* Allow for real %ss != %ds */ 172 173 popl %eax 174 ret 175 176/* 177 * prot_to_real() 178 * 179 * Switch CPU back to 16bit real mode in order to call system bios functions. 180 * 181 * All registers are preserved, except that %sp may be changed so that 182 * %ss:%sp points to the same memory. 183 * Note that %ebp is preserved and will not reference the correct part 184 * of the stack. 185 * 186 * Interrupts are enabled while in real mode. 187 * 188 * Based on the descripton in section 14.5 of the 80386 Programmer's 189 * reference book. 190 */ 191ENTRY(prot_to_real) 192 .code32 193 pushl %eax 194 195 /* 196 * Load the segment registers while still in protected mode. 197 * Otherwise the control bits don't get changed. 198 * The correct base addresses are loaded later. 199 */ 200 movw $bootrealdata, %ax 201 movw %ax, %ds 202 movw %ax, %es 203 movw %ax, %ss 204 205 /* 206 * Load %cs with a segment that has the correct attributes for 207 * 16bit operation. 208 */ 209 ljmp $bootrealseg, $1f 2101: 211 212 .code16 213 movl %cr0, %eax 214 and $~CR0_PE, %eax 215 movl %eax, %cr0 /* Disable potected mode */ 216 217 /* Jump far indirect to load real mode %cs */ 218 ljmp *%cs:toreal 219xreal: 220 /* 221 * CPU is now in real mode, load the other segment registers 222 * with their correct base addresses. 223 */ 224 mov %cs, %ax 225 mov %ax, %ds 226 mov %ax, %es 227 /* 228 * If stack was above 64k, 16bit %ss needs to be different from 229 * 32bit %ss (and the other segment registers). 230 */ 231 mov stkseg, %ax 232 mov %ax, %ss 233 subl stkdif, %esp 234 235 /* Check we are returning to an address below 64k */ 236 push %bp 237 movw %sp, %bp 238 movw 2/*bp*/ + 4/*eax*/ + 2(%bp), %ax /* high bits ret addr */ 239 test %ax, %ax 240 jne 1f 241 pop %bp 242 243 sti 244 popl %eax 245 retl 246 2471: movw $3f, %si 248 call message 249 movl 2/*bp*/ + 4/*eax*/(%bp), %eax /* return address */ 250 call dump_eax 251 int $0x18 2522: sti 253 hlt 254 jmp 2b 2553: .asciz "prot_to_real can't return to " 256 257 .global dump_eax_buff 258dump_eax_buff: 259 . = . + 16 260 261/* vtophys(void *) 262 * convert boot time 'linear' address to a physical one 263 */ 264 265ENTRY(vtophys) 266 .code32 267 xorl %eax, %eax 268 movw ourseg, %ax 269 shll $4, %eax 270 addl 4(%esp), %eax 271 ret 272