Annotation of src/sys/arch/i386/stand/lib/realprot.S, Revision 1.10
1.10 ! jakllsch 1: /* $NetBSD: realprot.S,v 1.9 2009/11/21 11:54:47 dsl Exp $ */
1.1 dsl 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: *
19: * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20: * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21: * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22: * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24: * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25: * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26: * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27: * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28: * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29: * POSSIBILITY OF SUCH DAMAGE.
30: */
31:
32: /*
33: * Loosely based on code from stand/lib/libcrt/bootsect/start_bootsect.S
34: */
35:
36: #include <machine/asm.h>
37:
38: #define CR0_PE 1
39:
40: .text
41: .align 16
42: gdt:
43: .word 0, 0
44: .byte 0, 0x00, 0x00, 0
45:
46: /* kernel code segment */
47: .globl flatcodeseg
48: flatcodeseg = . - gdt
49: .word 0xffff, 0
50: .byte 0, 0x9f, 0xcf, 0
51:
52: /* kernel data segment */
53: .globl flatdataseg
54: flatdataseg = . - gdt
55: .word 0xffff, 0
56: .byte 0, 0x93, 0xcf, 0
57:
58: /* boot code segment, base will be patched */
59: bootcodeseg = . - gdt
60: .word 0xffff, 0
61: .byte 0, 0x9e, 0x4f, 0
62:
63: /* boot data segment, base will be patched */
64: bootdataseg = . - gdt
65: .word 0xffff, 0
1.8 jmcneill 66: .byte 0, 0x92, 0xcf, 0
1.1 dsl 67:
68: /* 16 bit real mode, base will be patched */
69: bootrealseg = . - gdt
70: .word 0xffff, 0
71: .byte 0, 0x9e, 0x00, 0
72:
73: /* limits (etc) for data segment in real mode */
74: bootrealdata = . - gdt
75: .word 0xffff, 0
76: .byte 0, 0x92, 0x00, 0
77: gdtlen = . - gdt
78:
79: .align 16
80: gdtarg:
81: .word gdtlen-1 /* limit */
82: .long 0 /* physical addr, will be inserted */
83:
84: toreal: .word xreal /* off:seg address for indirect jump */
85: ourseg: .word 0 /* real mode code and data segment */
86:
87: stkseg: .word 0 /* real mode stack segment */
88: stkdif: .long 0 /* diff. between real and prot sp */
89:
90: .global gdt_fixup
91: gdt_fixup:
92: .code16
1.10 ! jakllsch 93: pushl %eax
! 94: pushl %edx
1.1 dsl 95:
96: xorl %eax, %eax
97: mov %cs, %ax
98: mov %ax, ourseg
99: /* sort out stuff for %ss != %ds */
1.10 ! jakllsch 100: xorl %edx, %edx
1.1 dsl 101: movw %ss, %dx
102: movw %dx, stkseg
1.10 ! jakllsch 103: subl %eax, %edx
! 104: shll $4, %edx
1.1 dsl 105: movl %edx, stkdif
106:
107: /* fix up GDT entries for bootstrap */
108: mov %ax, %dx
109: shll $4, %eax
110: shr $12, %dx
111:
112: #define FIXUP(gdt_index) \
113: movw %ax, gdt+gdt_index+2; \
114: movb %dl, gdt+gdt_index+4
115:
116: FIXUP(bootcodeseg)
117: FIXUP(bootrealseg)
118: FIXUP(bootdataseg)
119:
120: /* fix up GDT pointer */
121: addl $gdt, %eax
122: movl %eax, gdtarg+2
123:
1.10 ! jakllsch 124: popl %edx
! 125: popl %eax
1.1 dsl 126: ret
127:
128: /*
129: * real_to_prot()
130: *
1.3 wiz 131: * Switch CPU to 32bit protected mode to execute C.
1.1 dsl 132: *
133: * NB: Call with the 32bit calll instruction so that a 32 bit
134: * return address is pushed.
135: *
136: * All registers are preserved, %ss:%esp will point to the same
137: * place as %ss:%sp did, although the actual value of %esp might
138: * be changed.
139: *
140: * Interrupts are disabled while we are in 32bit mode to save us
141: * having to setup a different IDT. This code is only used during
142: * the boot process and it doesn't use any interrupts.
143: */
144: ENTRY(real_to_prot)
145: .code16
146: pushl %eax
147: cli
148:
149: lgdt %cs:gdtarg /* Global descriptor table */
150:
151: movl %cr0, %eax
152: or $CR0_PE, %ax
1.2 dsl 153: movl %eax, %cr0 /* Enter 'protected mode' */
1.1 dsl 154:
155: ljmp $bootcodeseg, $1f /* Jump into a 32bit segment */
156: 1:
157:
158: .code32
159: /* Set all the segment registers to map the same area as the code */
160: mov $bootdataseg, %eax
161: mov %ax, %ds
162: mov %ax, %es
163: mov %ax, %ss
164: addl stkdif, %esp /* Allow for real %ss != %ds */
165:
166: popl %eax
167: ret
168:
169: /*
170: * prot_to_real()
171: *
1.3 wiz 172: * Switch CPU back to 16bit real mode in order to call system bios functions.
1.1 dsl 173: *
174: * All registers are preserved, except that %sp may be changed so that
175: * %ss:%sp points to the same memory.
176: * Note that %ebp is preserved and will not reference the correct part
177: * of the stack.
178: *
179: * Interrupts are enabled while in real mode.
180: *
181: * Based on the descripton in section 14.5 of the 80386 Programmer's
182: * reference book.
183: */
1.4 gavan 184: /*
185: * EPIA_HACK
186: *
1.9 dsl 187: * VIA C3 processors (Eden, Samuel 2) don't seem to correctly switch back to
188: * executing 16 bit code after the switch to real mode and subsequent jump.
1.4 gavan 189: *
190: * It is speculated that the CPU is prefetching and decoding branch
191: * targets and not invalidating this buffer on the long jump.
1.9 dsl 192: * Further investication indicates that the caching of return addresses
193: * is most likely the problem.
1.4 gavan 194: *
1.9 dsl 195: * Previous versions just used some extra call/ret and a few NOPs, these
196: * only helped a bit, but booting compressed kernels would still fail.
1.4 gavan 197: *
1.9 dsl 198: * Trashing the return address stack (by doing 'call' without matched 'ret')
199: * Seems to fix things completely. 1 iteration isn't enough, 16 is plenty.
1.4 gavan 200: */
1.1 dsl 201: ENTRY(prot_to_real)
1.9 dsl 202: .code32
203: pushl %eax
1.4 gavan 204: #ifdef EPIA_HACK
1.9 dsl 205: push %ecx
206: push $0x10
207: pop %ecx
208: 1: call trash_return_cache
209: loop 1b
210: pop %ecx
1.4 gavan 211: #endif
1.1 dsl 212:
213: /*
214: * Load the segment registers while still in protected mode.
215: * Otherwise the control bits don't get changed.
216: * The correct base addresses are loaded later.
217: */
1.5 junyoung 218: movw $bootrealdata, %ax
1.1 dsl 219: movw %ax, %ds
220: movw %ax, %es
221: movw %ax, %ss
222:
223: /*
224: * Load %cs with a segment that has the correct attributes for
225: * 16bit operation.
226: */
227: ljmp $bootrealseg, $1f
228: 1:
229:
230: .code16
231: movl %cr0, %eax
232: and $~CR0_PE, %eax
233: movl %eax, %cr0 /* Disable potected mode */
234:
235: /* Jump far indirect to load real mode %cs */
236: ljmp *%cs:toreal
237: xreal:
238: /*
1.3 wiz 239: * CPU is now in real mode, load the other segment registers
1.1 dsl 240: * with their correct base addresses.
241: */
242: mov %cs, %ax
243: mov %ax, %ds
244: mov %ax, %es
245: /*
246: * If stack was above 64k, 16bit %ss needs to be different from
247: * 32bit %ss (and the other segment registers).
248: */
249: mov stkseg, %ax
250: mov %ax, %ss
251: subl stkdif, %esp
252:
253: /* Check we are returning to an address below 64k */
254: push %bp
255: movw %sp, %bp
256: movw 2/*bp*/ + 4/*eax*/ + 2(%bp), %ax /* high bits ret addr */
257: test %ax, %ax
258: jne 1f
259: pop %bp
260:
261: sti
262: popl %eax
263: retl
264:
265: 1: movw $3f, %si
266: call message
267: movl 2/*bp*/ + 4/*eax*/(%bp), %eax /* return address */
268: call dump_eax
269: int $0x18
270: 2: sti
271: hlt
272: jmp 2b
273: 3: .asciz "prot_to_real can't return to "
274:
275: .global dump_eax_buff
276: dump_eax_buff:
277: . = . + 16
278:
1.4 gavan 279: #ifdef EPIA_HACK
1.9 dsl 280: trash_return_cache:
281: .code32
282: pop %eax
283: jmp *%eax
1.4 gavan 284: #endif
285:
1.1 dsl 286: /* vtophys(void *)
287: * convert boot time 'linear' address to a physical one
288: */
289:
290: ENTRY(vtophys)
291: .code32
292: xorl %eax, %eax
293: movw ourseg, %ax
294: shll $4, %eax
295: addl 4(%esp), %eax
296: ret
CVSweb <webmaster@jp.NetBSD.org>