biostramp.S revision 1.4 1 1.4 jtk /* $NetBSD: biostramp.S,v 1.4 1996/09/13 00:02:38 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 #include "assym.h"
61 1.4 jtk
62 1.4 jtk #include <i386/include/param.h>
63 1.4 jtk #include <i386/include/specialreg.h>
64 1.4 jtk #include <i386/include/segments.h>
65 1.4 jtk #include <i386/include/apmvar.h>
66 1.4 jtk #include <i386/include/psl.h>
67 1.4 jtk #include <i386/include/asm.h>
68 1.4 jtk
69 1.3 mycroft #define addr32 .byte 0x67
70 1.3 mycroft #define data32 .byte 0x66
71 1.1 jtk
72 1.1 jtk .set MYBASE,NBPG
73 1.1 jtk .set MYSCRATCH,NBPG+NBPG
74 1.1 jtk .set CR3_ADDR,(MYSCRATCH-4)
75 1.1 jtk .set IDTR_SAVE_ADDR,CR3_ADDR-6
76 1.1 jtk .set GDTR_SAVE_ADDR,IDTR_SAVE_ADDR-6
77 1.1 jtk .set GDTR_LOCAL_ADDR,GDTR_SAVE_ADDR-6
78 1.1 jtk .set STACK_PTR_ADDR,GDTR_LOCAL_ADDR-4
79 1.1 jtk .set BASE_PTR_ADDR,STACK_PTR_ADDR-4
80 1.1 jtk .set FUNCTION_ADDR,(BASE_PTR_ADDR-2)
81 1.1 jtk .set GDT_COPY_ADDR,(FUNCTION_ADDR-NGDT*8)
82 1.1 jtk .set AX_REGADDR,(GDT_COPY_ADDR-2)
83 1.1 jtk .set BX_REGADDR,(AX_REGADDR-2)
84 1.1 jtk .set CX_REGADDR,(BX_REGADDR-2)
85 1.1 jtk .set DX_REGADDR,(CX_REGADDR-2)
86 1.1 jtk .set SI_REGADDR,(DX_REGADDR-2)
87 1.1 jtk .set DI_REGADDR,(SI_REGADDR-2)
88 1.1 jtk .set FLAGS_REGADDR,(DI_REGADDR-2)
89 1.1 jtk .set ENDREGADDR,(FLAGS_REGADDR-2)
90 1.1 jtk
91 1.1 jtk .set REALSTACK,ENDREGADDR-16 # leave a red zone?
92 1.1 jtk
93 1.1 jtk #define COPY_FLAGS (PSL_C|PSL_PF|PSL_AF|PSL_Z|PSL_N|PSL_D|PSL_V)
94 1.1 jtk
95 1.1 jtk /*
96 1.1 jtk * do_bios_call(int function, struct apmregs *regs)
97 1.1 jtk */
98 1.1 jtk
99 1.1 jtk ENTRY(do_bios_call)
100 1.1 jtk pushl %ebp
101 1.1 jtk movl %esp,%ebp /* set up frame ptr */
102 1.1 jtk pushl %esi
103 1.1 jtk pushl %edi
104 1.1 jtk pushl %ebx
105 1.1 jtk pushl %ds
106 1.1 jtk pushl %es
107 1.1 jtk pushl %fs
108 1.1 jtk pushl %gs
109 1.1 jtk
110 1.1 jtk # copy data to where the real-mode hook can handle it
111 1.1 jtk movl 8(%ebp),%eax
112 1.1 jtk movw %ax,FUNCTION_ADDR
113 1.1 jtk movl 12(%ebp),%ebx
114 1.1 jtk movw APMREG_AX(%ebx),%ax
115 1.1 jtk movw %ax,AX_REGADDR
116 1.1 jtk movw APMREG_BX(%ebx),%ax
117 1.1 jtk movw %ax,BX_REGADDR
118 1.1 jtk movw APMREG_CX(%ebx),%ax
119 1.1 jtk movw %ax,CX_REGADDR
120 1.1 jtk movw APMREG_DX(%ebx),%ax
121 1.1 jtk movw %ax,DX_REGADDR
122 1.1 jtk movw APMREG_SI(%ebx),%ax
123 1.1 jtk movw %ax,SI_REGADDR
124 1.1 jtk movw APMREG_DI(%ebx),%ax
125 1.1 jtk movw %ax,DI_REGADDR
126 1.1 jtk # merge current flags with certain provided flags
127 1.1 jtk movw APMREG_FLAGS(%ebx),%cx
128 1.1 jtk pushfl
129 1.1 jtk popl %eax
130 1.1 jtk andl $~(COPY_FLAGS|PSL_I),%eax
131 1.1 jtk andl $COPY_FLAGS,%ecx
132 1.1 jtk orl %ecx,%eax
133 1.1 jtk movw %ax,FLAGS_REGADDR
134 1.1 jtk
135 1.1 jtk # save flags, disable interrupts, do real mode stuff
136 1.1 jtk pushfl
137 1.1 jtk
138 1.1 jtk # save GDT
139 1.1 jtk sgdt GDTR_SAVE_ADDR
140 1.1 jtk
141 1.1 jtk # copy the GDT to local area
142 1.1 jtk movl GDTR_SAVE_ADDR+2,%esi
143 1.1 jtk movl $GDT_COPY_ADDR,%edi
144 1.1 jtk movl $(NGDT*8),%ecx
145 1.1 jtk cld
146 1.1 jtk rep
147 1.1 jtk movsb
148 1.1 jtk movw $(NGDT*8)-1,GDTR_LOCAL_ADDR
149 1.1 jtk movl $GDT_COPY_ADDR,GDTR_LOCAL_ADDR+2
150 1.1 jtk
151 1.1 jtk # install GDT copy
152 1.1 jtk lgdt GDTR_LOCAL_ADDR
153 1.1 jtk
154 1.1 jtk cli
155 1.1 jtk
156 1.1 jtk # save IDT
157 1.1 jtk sidt IDTR_SAVE_ADDR
158 1.1 jtk
159 1.1 jtk # set up new stack: save old ones, create new segs
160 1.1 jtk movl %esp,STACK_PTR_ADDR
161 1.1 jtk movl %ebp,BASE_PTR_ADDR
162 1.1 jtk movl $REALSTACK,%esp
163 1.1 jtk movl $0,%ebp # leave no trace, there is none.
164 1.1 jtk
165 1.1 jtk # save CR3
166 1.1 jtk movl %cr3,%eax
167 1.1 jtk movl %eax,CR3_ADDR
168 1.1 jtk
169 1.1 jtk # turn off paging
170 1.1 jtk movl %cr0,%eax
171 1.1 jtk andl $~(CR0_PG),%eax
172 1.1 jtk movl %eax,%cr0
173 1.1 jtk
174 1.1 jtk # flush TLB, drop PDBR
175 1.1 jtk xorl %eax,%eax
176 1.1 jtk movl %eax,%cr3
177 1.1 jtk
178 1.1 jtk ## load 16-bit segment descriptors
179 1.1 jtk movw $GSEL(GBIOSDATA_SEL,SEL_KPL),%bx
180 1.1 jtk movw %bx,%ds
181 1.1 jtk movw %bx,%es
182 1.1 jtk movw %bx,%fs
183 1.1 jtk movw %bx,%gs
184 1.1 jtk
185 1.1 jtk ljmp $GSEL(GBIOSCODE_SEL,SEL_KPL),$x16+MYBASE
186 1.1 jtk
187 1.1 jtk x16:
188 1.1 jtk # turn off protected mode--yikes!
189 1.1 jtk mov %cr0,%eax
190 1.1 jtk data32
191 1.1 jtk and $~CR0_PE,%eax
192 1.1 jtk mov %eax,%cr0
193 1.1 jtk
194 1.1 jtk # need inter-segment jump to reload real-mode CS
195 1.1 jtk data32
196 1.1 jtk ljmp $(MYBASE>>4),$xreal
197 1.1 jtk
198 1.1 jtk xreal: # really in real mode now
199 1.1 jtk # set up segment selectors. Note: everything is now relative
200 1.1 jtk # to zero-base in this file, except %ss.
201 1.1 jtk # data items in our scratch area need to reflect MYADDR
202 1.1 jtk xorl %ax,%ax
203 1.1 jtk movw %ax,%ss
204 1.1 jtk
205 1.1 jtk movw %cs,%ax
206 1.1 jtk movw %ax,%es
207 1.1 jtk movw %ax,%fs
208 1.1 jtk movw %ax,%gs
209 1.1 jtk movw %ax,%ds
210 1.1 jtk
211 1.1 jtk ## load IDT, now that we are here.
212 1.1 jtk addr32
213 1.1 jtk lidt IDT_bios
214 1.1 jtk
215 1.1 jtk # Don't forget that we're in real mode, with 16-bit default data.
216 1.1 jtk # all these movl's are really movw's !
217 1.1 jtk addr32
218 1.1 jtk movl DI_REGADDR-MYBASE,%edi
219 1.1 jtk addr32
220 1.1 jtk movl SI_REGADDR-MYBASE,%esi
221 1.1 jtk addr32
222 1.1 jtk movl DX_REGADDR-MYBASE,%edx
223 1.1 jtk addr32
224 1.1 jtk movl CX_REGADDR-MYBASE,%ecx
225 1.1 jtk addr32
226 1.1 jtk movl BX_REGADDR-MYBASE,%ebx
227 1.1 jtk addr32
228 1.1 jtk movb FUNCTION_ADDR-MYBASE,%al
229 1.1 jtk addr32
230 1.1 jtk movb %al,intaddr+1 # self modifying code, yuck. no indirect interrupt instruction!
231 1.1 jtk # long jump to flush processor cache to reflect code modification
232 1.1 jtk data32
233 1.1 jtk ljmp $(MYBASE>>4),$flushit
234 1.1 jtk flushit:
235 1.1 jtk addr32
236 1.1 jtk movl FLAGS_REGADDR-MYBASE,%eax
237 1.1 jtk pushl %eax
238 1.1 jtk popfl
239 1.1 jtk addr32
240 1.1 jtk movl AX_REGADDR-MYBASE,%eax
241 1.1 jtk
242 1.1 jtk intaddr:
243 1.1 jtk int $0xff
244 1.1 jtk
245 1.1 jtk # save results
246 1.1 jtk pushf
247 1.1 jtk addr32
248 1.1 jtk movl %eax,AX_REGADDR-MYBASE
249 1.1 jtk addr32
250 1.1 jtk movl %ebx,BX_REGADDR-MYBASE
251 1.1 jtk addr32
252 1.1 jtk movl %ecx,CX_REGADDR-MYBASE
253 1.1 jtk addr32
254 1.1 jtk movl %edx,DX_REGADDR-MYBASE
255 1.1 jtk addr32
256 1.1 jtk movl %esi,SI_REGADDR-MYBASE
257 1.1 jtk addr32
258 1.1 jtk movl %edi,DI_REGADDR-MYBASE
259 1.1 jtk pop %eax
260 1.1 jtk addr32
261 1.1 jtk movl %eax,FLAGS_REGADDR-MYBASE
262 1.1 jtk
263 1.1 jtk # and return to protected mode
264 1.1 jtk cli # just to be sure
265 1.1 jtk
266 1.1 jtk mov %cr0,%eax
267 1.1 jtk data32
268 1.1 jtk or $CR0_PE,%eax
269 1.1 jtk mov %eax,%cr0
270 1.1 jtk
271 1.1 jtk # long jump to 32-bit code segment
272 1.1 jtk data32
273 1.1 jtk ljmp $GSEL(GCODE_SEL,SEL_KPL),$x32+MYBASE
274 1.1 jtk x32:
275 1.1 jtk #back in 32-bit mode/protected mode (but not paging yet).
276 1.1 jtk # Reload the segment registers & IDT
277 1.1 jtk
278 1.1 jtk movw $GSEL(GDATA_SEL,SEL_KPL),%bx
279 1.1 jtk movw %bx,%ds
280 1.1 jtk movw %bx,%ss
281 1.1 jtk movw %bx,%es
282 1.1 jtk
283 1.1 jtk # reload PDBR
284 1.1 jtk movl CR3_ADDR,%eax
285 1.1 jtk movl %eax,%cr3
286 1.1 jtk movl %cr0,%eax
287 1.1 jtk orl $CR0_PG,%eax
288 1.1 jtk movl %eax,%cr0
289 1.1 jtk
290 1.1 jtk # reload system copy of GDT
291 1.1 jtk lgdt GDTR_SAVE_ADDR
292 1.1 jtk
293 1.1 jtk # restore protected-mode stack
294 1.1 jtk movl STACK_PTR_ADDR,%esp
295 1.1 jtk movl BASE_PTR_ADDR,%ebp
296 1.1 jtk
297 1.1 jtk #restore protected-mode IDT
298 1.1 jtk lidt IDTR_SAVE_ADDR
299 1.1 jtk
300 1.1 jtk # copy back arguments from holding pen
301 1.1 jtk
302 1.1 jtk movl 12(%ebp),%ebx
303 1.1 jtk movw AX_REGADDR,%ax
304 1.1 jtk movw %ax,APMREG_AX(%ebx)
305 1.1 jtk movw BX_REGADDR,%ax
306 1.1 jtk movw %ax,APMREG_BX(%ebx)
307 1.1 jtk movw CX_REGADDR,%ax
308 1.1 jtk movw %ax,APMREG_CX(%ebx)
309 1.1 jtk movw DX_REGADDR,%ax
310 1.1 jtk movw %ax,APMREG_DX(%ebx)
311 1.1 jtk movw SI_REGADDR,%ax
312 1.1 jtk movw %ax,APMREG_SI(%ebx)
313 1.1 jtk movw DI_REGADDR,%ax
314 1.1 jtk movw %ax,APMREG_DI(%ebx)
315 1.1 jtk movw FLAGS_REGADDR,%ax
316 1.1 jtk movw %ax,APMREG_FLAGS(%ebx)
317 1.1 jtk
318 1.1 jtk # finish up, restore registers, and return
319 1.1 jtk popfl
320 1.1 jtk popl %gs
321 1.1 jtk popl %fs
322 1.1 jtk popl %es
323 1.1 jtk popl %ds # see above
324 1.1 jtk popl %ebx
325 1.1 jtk popl %edi
326 1.1 jtk popl %esi
327 1.1 jtk leave
328 1.1 jtk ret
329 1.1 jtk
330 1.1 jtk .align 4
331 1.1 jtk IDT_bios: # BIOS IDT descriptor (real-mode)
332 1.1 jtk .word 1023
333 1.1 jtk .long 0
334