biostramp.S revision 1.1 1 1.1 jtk /* $NetBSD: biostramp.S,v 1.1 1996/09/08 15:36:53 jtk Exp $ */
2 1.1 jtk /*-
3 1.1 jtk * Copyright (c) 1996 John T. Kohl. All rights reserved.
4 1.1 jtk *
5 1.1 jtk * Redistribution and use in source and binary forms, with or without
6 1.1 jtk * modification, are permitted provided that the following conditions
7 1.1 jtk * are met:
8 1.1 jtk * 1. Redistributions of source code must retain the above copyright
9 1.1 jtk * notice, this list of conditions and the following disclaimer.
10 1.1 jtk * 2. Redistributions in binary form must reproduce the above copyright
11 1.1 jtk * notice, this list of conditions and the following disclaimer in the
12 1.1 jtk * documentation and/or other materials provided with the distribution.
13 1.1 jtk * 3. All advertising materials mentioning features or use of this software
14 1.1 jtk * must display the following acknowledgement:
15 1.1 jtk * This product includes software developed by the University of
16 1.1 jtk * California, Berkeley and its contributors.
17 1.1 jtk * 4. Neither the name of the University nor the names of its contributors
18 1.1 jtk * may be used to endorse or promote products derived from this software
19 1.1 jtk * without specific prior written permission.
20 1.1 jtk *
21 1.1 jtk * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR
22 1.1 jtk * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
23 1.1 jtk * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
24 1.1 jtk * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
25 1.1 jtk * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
26 1.1 jtk * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
27 1.1 jtk * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 1.1 jtk * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
29 1.1 jtk * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
30 1.1 jtk * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31 1.1 jtk * POSSIBILITY OF SUCH DAMAGE.
32 1.1 jtk *
33 1.1 jtk */
34 1.1 jtk
35 1.1 jtk /*
36 1.1 jtk * biostramp.S: provide a means for NetBSD to call BIOS interrupts
37 1.1 jtk * by switching to real mode, calling it, and switching
38 1.1 jtk * back to protected & paging mode.
39 1.1 jtk */
40 1.1 jtk
41 1.1 jtk /*
42 1.1 jtk * Micro$haft's book on i386/i486 programming says you should do the following
43 1.1 jtk * to return to real mode from protected mode:
44 1.1 jtk *
45 1.1 jtk * 1) disable paging, by jumping to code with identical virtual and physical
46 1.1 jtk * addresses, clearing PG in CR0, and zeroing CR3 (PDBR).
47 1.1 jtk *
48 1.1 jtk * 2) segment descriptors must be byte-granular with limit 64k-1, def32 = 0,
49 1.1 jtk * (i.e. 16-bit data accesses and/or 80286 instructions)
50 1.1 jtk * CS must be executable; DS,ES,FS,GS should be writable
51 1.1 jtk *
52 1.1 jtk * 3) disable interrupts, load IDTR with original value (base 0, limit 1023)
53 1.1 jtk *
54 1.1 jtk * 4) clear PE in CR0, execute FAR jump to load CS.
55 1.1 jtk *
56 1.1 jtk * 5) load SP, and off you go
57 1.1 jtk *
58 1.1 jtk */
59 1.1 jtk
60 1.1 jtk #define ASM
61 1.1 jtk #define _LOCORE
62 1.1 jtk
63 1.1 jtk #define addr32 .byte 0x67
64 1.1 jtk #define data32 .byte 0x66
65 1.1 jtk
66 1.1 jtk /* these from locore.s: */
67 1.1 jtk #define ALIGN_TEXT .align 2,0x90 /* 4-byte boundaries, NOP-filled */
68 1.1 jtk #define ENTRY(name) .globl _ ## name; ALIGN_TEXT; _ ## name:
69 1.1 jtk
70 1.1 jtk #include "assym.h"
71 1.1 jtk #include <machine/param.h>
72 1.1 jtk #include <machine/specialreg.h>
73 1.1 jtk #include <machine/segments.h>
74 1.1 jtk #include <machine/apmvar.h>
75 1.1 jtk #include <machine/psl.h>
76 1.1 jtk
77 1.1 jtk .set MYBASE,NBPG
78 1.1 jtk .set MYSCRATCH,NBPG+NBPG
79 1.1 jtk .set CR3_ADDR,(MYSCRATCH-4)
80 1.1 jtk .set IDTR_SAVE_ADDR,CR3_ADDR-6
81 1.1 jtk .set GDTR_SAVE_ADDR,IDTR_SAVE_ADDR-6
82 1.1 jtk .set GDTR_LOCAL_ADDR,GDTR_SAVE_ADDR-6
83 1.1 jtk .set STACK_PTR_ADDR,GDTR_LOCAL_ADDR-4
84 1.1 jtk .set BASE_PTR_ADDR,STACK_PTR_ADDR-4
85 1.1 jtk .set FUNCTION_ADDR,(BASE_PTR_ADDR-2)
86 1.1 jtk .set GDT_COPY_ADDR,(FUNCTION_ADDR-NGDT*8)
87 1.1 jtk .set AX_REGADDR,(GDT_COPY_ADDR-2)
88 1.1 jtk .set BX_REGADDR,(AX_REGADDR-2)
89 1.1 jtk .set CX_REGADDR,(BX_REGADDR-2)
90 1.1 jtk .set DX_REGADDR,(CX_REGADDR-2)
91 1.1 jtk .set SI_REGADDR,(DX_REGADDR-2)
92 1.1 jtk .set DI_REGADDR,(SI_REGADDR-2)
93 1.1 jtk .set FLAGS_REGADDR,(DI_REGADDR-2)
94 1.1 jtk .set ENDREGADDR,(FLAGS_REGADDR-2)
95 1.1 jtk
96 1.1 jtk .set REALSTACK,ENDREGADDR-16 # leave a red zone?
97 1.1 jtk
98 1.1 jtk #define COPY_FLAGS (PSL_C|PSL_PF|PSL_AF|PSL_Z|PSL_N|PSL_D|PSL_V)
99 1.1 jtk
100 1.1 jtk /*
101 1.1 jtk * do_bios_call(int function, struct apmregs *regs)
102 1.1 jtk */
103 1.1 jtk
104 1.1 jtk ENTRY(do_bios_call)
105 1.1 jtk pushl %ebp
106 1.1 jtk movl %esp,%ebp /* set up frame ptr */
107 1.1 jtk pushl %esi
108 1.1 jtk pushl %edi
109 1.1 jtk pushl %ebx
110 1.1 jtk pushl %ds
111 1.1 jtk pushl %es
112 1.1 jtk pushl %fs
113 1.1 jtk pushl %gs
114 1.1 jtk
115 1.1 jtk # copy data to where the real-mode hook can handle it
116 1.1 jtk movl 8(%ebp),%eax
117 1.1 jtk movw %ax,FUNCTION_ADDR
118 1.1 jtk movl 12(%ebp),%ebx
119 1.1 jtk movw APMREG_AX(%ebx),%ax
120 1.1 jtk movw %ax,AX_REGADDR
121 1.1 jtk movw APMREG_BX(%ebx),%ax
122 1.1 jtk movw %ax,BX_REGADDR
123 1.1 jtk movw APMREG_CX(%ebx),%ax
124 1.1 jtk movw %ax,CX_REGADDR
125 1.1 jtk movw APMREG_DX(%ebx),%ax
126 1.1 jtk movw %ax,DX_REGADDR
127 1.1 jtk movw APMREG_SI(%ebx),%ax
128 1.1 jtk movw %ax,SI_REGADDR
129 1.1 jtk movw APMREG_DI(%ebx),%ax
130 1.1 jtk movw %ax,DI_REGADDR
131 1.1 jtk # merge current flags with certain provided flags
132 1.1 jtk movw APMREG_FLAGS(%ebx),%cx
133 1.1 jtk pushfl
134 1.1 jtk popl %eax
135 1.1 jtk andl $~(COPY_FLAGS|PSL_I),%eax
136 1.1 jtk andl $COPY_FLAGS,%ecx
137 1.1 jtk orl %ecx,%eax
138 1.1 jtk movw %ax,FLAGS_REGADDR
139 1.1 jtk
140 1.1 jtk # save flags, disable interrupts, do real mode stuff
141 1.1 jtk pushfl
142 1.1 jtk
143 1.1 jtk # save GDT
144 1.1 jtk sgdt GDTR_SAVE_ADDR
145 1.1 jtk
146 1.1 jtk # copy the GDT to local area
147 1.1 jtk movl GDTR_SAVE_ADDR+2,%esi
148 1.1 jtk movl $GDT_COPY_ADDR,%edi
149 1.1 jtk movl $(NGDT*8),%ecx
150 1.1 jtk cld
151 1.1 jtk rep
152 1.1 jtk movsb
153 1.1 jtk movw $(NGDT*8)-1,GDTR_LOCAL_ADDR
154 1.1 jtk movl $GDT_COPY_ADDR,GDTR_LOCAL_ADDR+2
155 1.1 jtk
156 1.1 jtk # install GDT copy
157 1.1 jtk lgdt GDTR_LOCAL_ADDR
158 1.1 jtk
159 1.1 jtk cli
160 1.1 jtk
161 1.1 jtk # save IDT
162 1.1 jtk sidt IDTR_SAVE_ADDR
163 1.1 jtk
164 1.1 jtk # set up new stack: save old ones, create new segs
165 1.1 jtk movl %esp,STACK_PTR_ADDR
166 1.1 jtk movl %ebp,BASE_PTR_ADDR
167 1.1 jtk movl $REALSTACK,%esp
168 1.1 jtk movl $0,%ebp # leave no trace, there is none.
169 1.1 jtk
170 1.1 jtk # save CR3
171 1.1 jtk movl %cr3,%eax
172 1.1 jtk movl %eax,CR3_ADDR
173 1.1 jtk
174 1.1 jtk # turn off paging
175 1.1 jtk movl %cr0,%eax
176 1.1 jtk andl $~(CR0_PG),%eax
177 1.1 jtk movl %eax,%cr0
178 1.1 jtk
179 1.1 jtk # flush TLB, drop PDBR
180 1.1 jtk xorl %eax,%eax
181 1.1 jtk movl %eax,%cr3
182 1.1 jtk
183 1.1 jtk ## load 16-bit segment descriptors
184 1.1 jtk movw $GSEL(GBIOSDATA_SEL,SEL_KPL),%bx
185 1.1 jtk movw %bx,%ds
186 1.1 jtk movw %bx,%es
187 1.1 jtk movw %bx,%fs
188 1.1 jtk movw %bx,%gs
189 1.1 jtk
190 1.1 jtk ljmp $GSEL(GBIOSCODE_SEL,SEL_KPL),$x16+MYBASE
191 1.1 jtk
192 1.1 jtk x16:
193 1.1 jtk # turn off protected mode--yikes!
194 1.1 jtk mov %cr0,%eax
195 1.1 jtk data32
196 1.1 jtk and $~CR0_PE,%eax
197 1.1 jtk mov %eax,%cr0
198 1.1 jtk
199 1.1 jtk # need inter-segment jump to reload real-mode CS
200 1.1 jtk data32
201 1.1 jtk ljmp $(MYBASE>>4),$xreal
202 1.1 jtk
203 1.1 jtk xreal: # really in real mode now
204 1.1 jtk # set up segment selectors. Note: everything is now relative
205 1.1 jtk # to zero-base in this file, except %ss.
206 1.1 jtk # data items in our scratch area need to reflect MYADDR
207 1.1 jtk xorl %ax,%ax
208 1.1 jtk movw %ax,%ss
209 1.1 jtk
210 1.1 jtk movw %cs,%ax
211 1.1 jtk movw %ax,%es
212 1.1 jtk movw %ax,%fs
213 1.1 jtk movw %ax,%gs
214 1.1 jtk movw %ax,%ds
215 1.1 jtk
216 1.1 jtk ## load IDT, now that we are here.
217 1.1 jtk addr32
218 1.1 jtk lidt IDT_bios
219 1.1 jtk
220 1.1 jtk # Don't forget that we're in real mode, with 16-bit default data.
221 1.1 jtk # all these movl's are really movw's !
222 1.1 jtk addr32
223 1.1 jtk movl DI_REGADDR-MYBASE,%edi
224 1.1 jtk addr32
225 1.1 jtk movl SI_REGADDR-MYBASE,%esi
226 1.1 jtk addr32
227 1.1 jtk movl DX_REGADDR-MYBASE,%edx
228 1.1 jtk addr32
229 1.1 jtk movl CX_REGADDR-MYBASE,%ecx
230 1.1 jtk addr32
231 1.1 jtk movl BX_REGADDR-MYBASE,%ebx
232 1.1 jtk addr32
233 1.1 jtk movb FUNCTION_ADDR-MYBASE,%al
234 1.1 jtk addr32
235 1.1 jtk movb %al,intaddr+1 # self modifying code, yuck. no indirect interrupt instruction!
236 1.1 jtk # long jump to flush processor cache to reflect code modification
237 1.1 jtk data32
238 1.1 jtk ljmp $(MYBASE>>4),$flushit
239 1.1 jtk flushit:
240 1.1 jtk addr32
241 1.1 jtk movl FLAGS_REGADDR-MYBASE,%eax
242 1.1 jtk pushl %eax
243 1.1 jtk popfl
244 1.1 jtk addr32
245 1.1 jtk movl AX_REGADDR-MYBASE,%eax
246 1.1 jtk
247 1.1 jtk intaddr:
248 1.1 jtk int $0xff
249 1.1 jtk
250 1.1 jtk # save results
251 1.1 jtk pushf
252 1.1 jtk addr32
253 1.1 jtk movl %eax,AX_REGADDR-MYBASE
254 1.1 jtk addr32
255 1.1 jtk movl %ebx,BX_REGADDR-MYBASE
256 1.1 jtk addr32
257 1.1 jtk movl %ecx,CX_REGADDR-MYBASE
258 1.1 jtk addr32
259 1.1 jtk movl %edx,DX_REGADDR-MYBASE
260 1.1 jtk addr32
261 1.1 jtk movl %esi,SI_REGADDR-MYBASE
262 1.1 jtk addr32
263 1.1 jtk movl %edi,DI_REGADDR-MYBASE
264 1.1 jtk pop %eax
265 1.1 jtk addr32
266 1.1 jtk movl %eax,FLAGS_REGADDR-MYBASE
267 1.1 jtk
268 1.1 jtk # and return to protected mode
269 1.1 jtk cli # just to be sure
270 1.1 jtk
271 1.1 jtk mov %cr0,%eax
272 1.1 jtk data32
273 1.1 jtk or $CR0_PE,%eax
274 1.1 jtk mov %eax,%cr0
275 1.1 jtk
276 1.1 jtk # long jump to 32-bit code segment
277 1.1 jtk data32
278 1.1 jtk ljmp $GSEL(GCODE_SEL,SEL_KPL),$x32+MYBASE
279 1.1 jtk x32:
280 1.1 jtk #back in 32-bit mode/protected mode (but not paging yet).
281 1.1 jtk # Reload the segment registers & IDT
282 1.1 jtk
283 1.1 jtk movw $GSEL(GDATA_SEL,SEL_KPL),%bx
284 1.1 jtk movw %bx,%ds
285 1.1 jtk movw %bx,%ss
286 1.1 jtk movw %bx,%es
287 1.1 jtk
288 1.1 jtk # reload PDBR
289 1.1 jtk movl CR3_ADDR,%eax
290 1.1 jtk movl %eax,%cr3
291 1.1 jtk movl %cr0,%eax
292 1.1 jtk orl $CR0_PG,%eax
293 1.1 jtk movl %eax,%cr0
294 1.1 jtk
295 1.1 jtk # reload system copy of GDT
296 1.1 jtk lgdt GDTR_SAVE_ADDR
297 1.1 jtk
298 1.1 jtk # restore protected-mode stack
299 1.1 jtk movl STACK_PTR_ADDR,%esp
300 1.1 jtk movl BASE_PTR_ADDR,%ebp
301 1.1 jtk
302 1.1 jtk #restore protected-mode IDT
303 1.1 jtk lidt IDTR_SAVE_ADDR
304 1.1 jtk
305 1.1 jtk # copy back arguments from holding pen
306 1.1 jtk
307 1.1 jtk movl 12(%ebp),%ebx
308 1.1 jtk movw AX_REGADDR,%ax
309 1.1 jtk movw %ax,APMREG_AX(%ebx)
310 1.1 jtk movw BX_REGADDR,%ax
311 1.1 jtk movw %ax,APMREG_BX(%ebx)
312 1.1 jtk movw CX_REGADDR,%ax
313 1.1 jtk movw %ax,APMREG_CX(%ebx)
314 1.1 jtk movw DX_REGADDR,%ax
315 1.1 jtk movw %ax,APMREG_DX(%ebx)
316 1.1 jtk movw SI_REGADDR,%ax
317 1.1 jtk movw %ax,APMREG_SI(%ebx)
318 1.1 jtk movw DI_REGADDR,%ax
319 1.1 jtk movw %ax,APMREG_DI(%ebx)
320 1.1 jtk movw FLAGS_REGADDR,%ax
321 1.1 jtk movw %ax,APMREG_FLAGS(%ebx)
322 1.1 jtk
323 1.1 jtk # finish up, restore registers, and return
324 1.1 jtk popfl
325 1.1 jtk popl %gs
326 1.1 jtk popl %fs
327 1.1 jtk popl %es
328 1.1 jtk popl %ds # see above
329 1.1 jtk popl %ebx
330 1.1 jtk popl %edi
331 1.1 jtk popl %esi
332 1.1 jtk leave
333 1.1 jtk ret
334 1.1 jtk
335 1.1 jtk .align 4
336 1.1 jtk IDT_bios: # BIOS IDT descriptor (real-mode)
337 1.1 jtk .word 1023
338 1.1 jtk .long 0
339