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