xref: /dragonfly/stand/boot/pc32/btx/btx/btx.S (revision 479ab7f0)
1*479ab7f0SSascha Wildner/*
2*479ab7f0SSascha Wildner * Copyright (c) 2003,2004 The DragonFly Project.  All rights reserved.
3*479ab7f0SSascha Wildner *
4*479ab7f0SSascha Wildner * This code is derived from software contributed to The DragonFly Project
5*479ab7f0SSascha Wildner * by Matthew Dillon <dillon@backplane.com>
6*479ab7f0SSascha Wildner *
7*479ab7f0SSascha Wildner * Redistribution and use in source and binary forms, with or without
8*479ab7f0SSascha Wildner * modification, are permitted provided that the following conditions
9*479ab7f0SSascha Wildner * are met:
10*479ab7f0SSascha Wildner *
11*479ab7f0SSascha Wildner * 1. Redistributions of source code must retain the above copyright
12*479ab7f0SSascha Wildner *    notice, this list of conditions and the following disclaimer.
13*479ab7f0SSascha Wildner * 2. Redistributions in binary form must reproduce the above copyright
14*479ab7f0SSascha Wildner *    notice, this list of conditions and the following disclaimer in
15*479ab7f0SSascha Wildner *    the documentation and/or other materials provided with the
16*479ab7f0SSascha Wildner *    distribution.
17*479ab7f0SSascha Wildner * 3. Neither the name of The DragonFly Project nor the names of its
18*479ab7f0SSascha Wildner *    contributors may be used to endorse or promote products derived
19*479ab7f0SSascha Wildner *    from this software without specific, prior written permission.
20*479ab7f0SSascha Wildner *
21*479ab7f0SSascha Wildner * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22*479ab7f0SSascha Wildner * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23*479ab7f0SSascha Wildner * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24*479ab7f0SSascha Wildner * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
25*479ab7f0SSascha Wildner * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26*479ab7f0SSascha Wildner * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
27*479ab7f0SSascha Wildner * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28*479ab7f0SSascha Wildner * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
29*479ab7f0SSascha Wildner * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
30*479ab7f0SSascha Wildner * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
31*479ab7f0SSascha Wildner * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32*479ab7f0SSascha Wildner * SUCH DAMAGE.
33*479ab7f0SSascha Wildner *
34*479ab7f0SSascha Wildner * Copyright (c) 1998 Robert Nordier
35*479ab7f0SSascha Wildner * All rights reserved.
36*479ab7f0SSascha Wildner *
37*479ab7f0SSascha Wildner * Redistribution and use in source and binary forms are freely
38*479ab7f0SSascha Wildner * permitted provided that the above copyright notice and this
39*479ab7f0SSascha Wildner * paragraph and the following disclaimer are duplicated in all
40*479ab7f0SSascha Wildner * such forms.
41*479ab7f0SSascha Wildner *
42*479ab7f0SSascha Wildner * This software is provided "AS IS" and without any express or
43*479ab7f0SSascha Wildner * implied warranties, including, without limitation, the implied
44*479ab7f0SSascha Wildner * warranties of merchantability and fitness for a particular
45*479ab7f0SSascha Wildner * purpose.
46*479ab7f0SSascha Wildner *
47*479ab7f0SSascha Wildner * $FreeBSD: src/sys/boot/i386/btx/btx/btx.s,v 1.32 2002/10/08 18:19:02 jhb Exp $
48*479ab7f0SSascha Wildner * $DragonFly: src/sys/boot/pc32/btx/btx/btx.S,v 1.8 2006/01/18 09:59:34 swildner Exp $
49*479ab7f0SSascha Wildner */
50*479ab7f0SSascha Wildner
51*479ab7f0SSascha Wildner#include "../../bootasm.h"
52*479ab7f0SSascha Wildner
53*479ab7f0SSascha Wildner/*
54*479ab7f0SSascha Wildner * Paging control.
55*479ab7f0SSascha Wildner */
56*479ab7f0SSascha Wildner		.set PAG_SIZ,0x1000		# Page size
57*479ab7f0SSascha Wildner		.set PAG_CNT,0x1000		# Pages to map
58*479ab7f0SSascha Wildner/*
59*479ab7f0SSascha Wildner * Fields in %eflags.
60*479ab7f0SSascha Wildner */
61*479ab7f0SSascha Wildner		.set PSL_RESERVED_DEFAULT,0x00000002
62*479ab7f0SSascha Wildner		.set PSL_T,0x00000100		# Trap flag
63*479ab7f0SSascha Wildner		.set PSL_I,0x00000200		# Interrupt enable flag
64*479ab7f0SSascha Wildner		.set PSL_D,0x00000400		# String instruction direction
65*479ab7f0SSascha Wildner		.set PSL_NT,0x00004000		# Nested task flag
66*479ab7f0SSascha Wildner		.set PSL_VM,0x00020000		# Virtual 8086 mode flag
67*479ab7f0SSascha Wildner		.set PSL_AC,0x00040000		# Alignment check flag
68*479ab7f0SSascha Wildner
69*479ab7f0SSascha Wildner/*
70*479ab7f0SSascha Wildner * Segment selectors.
71*479ab7f0SSascha Wildner */
72*479ab7f0SSascha Wildner		.set SEL_SCODE,0x8		# Supervisor code
73*479ab7f0SSascha Wildner		.set SEL_SDATA,0x10		# Supervisor data
74*479ab7f0SSascha Wildner		.set SEL_RCODE,0x18		# Real mode code
75*479ab7f0SSascha Wildner		.set SEL_RDATA,0x20		# Real mode data
76*479ab7f0SSascha Wildner		.set SEL_UCODE,0x28|3		# User code
77*479ab7f0SSascha Wildner		.set SEL_UDATA,0x30|3		# User data
78*479ab7f0SSascha Wildner		.set SEL_TSS,0x38		# TSS
79*479ab7f0SSascha Wildner
80*479ab7f0SSascha Wildner/*
81*479ab7f0SSascha Wildner * Task state segment fields.
82*479ab7f0SSascha Wildner */
83*479ab7f0SSascha Wildner		.set TSS_ESP0,0x4		# PL 0 ESP
84*479ab7f0SSascha Wildner		.set TSS_SS0,0x8		# PL 0 SS
85*479ab7f0SSascha Wildner		.set TSS_MAP,0x66		# I/O bit map base
86*479ab7f0SSascha Wildner
87*479ab7f0SSascha Wildner/*
88*479ab7f0SSascha Wildner * System calls.
89*479ab7f0SSascha Wildner */
90*479ab7f0SSascha Wildner		.set SYS_EXIT,0x0		# Exit
91*479ab7f0SSascha Wildner		.set SYS_EXEC,0x1		# Exec
92*479ab7f0SSascha Wildner
93*479ab7f0SSascha Wildner/*
94*479ab7f0SSascha Wildner * Fields in V86 interface structure.
95*479ab7f0SSascha Wildner */
96*479ab7f0SSascha Wildner		.set V86_CTL,0x0		# Control flags
97*479ab7f0SSascha Wildner		.set V86_ADDR,0x4		# Int number/address
98*479ab7f0SSascha Wildner		.set V86_ES,0x8			# V86 ES
99*479ab7f0SSascha Wildner		.set V86_DS,0xc			# V86 DS
100*479ab7f0SSascha Wildner		.set V86_FS,0x10		# V86 FS
101*479ab7f0SSascha Wildner		.set V86_GS,0x14		# V86 GS
102*479ab7f0SSascha Wildner/*
103*479ab7f0SSascha Wildner * V86 control flags.
104*479ab7f0SSascha Wildner */
105*479ab7f0SSascha Wildner		.set V86F_ADDR,0x10000		# Segment:offset address
106*479ab7f0SSascha Wildner		.set V86F_CALLF,0x20000		# Emulate far call
107*479ab7f0SSascha Wildner		.set V86F_FLAGS,0x40000		# Return flags
108*479ab7f0SSascha Wildner
109*479ab7f0SSascha Wildner/*
110*479ab7f0SSascha Wildner * Dump format control bytes.
111*479ab7f0SSascha Wildner */
112*479ab7f0SSascha Wildner		.set DMP_X16,0x1		# Word
113*479ab7f0SSascha Wildner		.set DMP_X32,0x2		# Long
114*479ab7f0SSascha Wildner		.set DMP_MEM,0x4		# Memory
115*479ab7f0SSascha Wildner		.set DMP_EOL,0x8		# End of line
116*479ab7f0SSascha Wildner
117*479ab7f0SSascha Wildner/*
118*479ab7f0SSascha Wildner * Screen defaults and assumptions.
119*479ab7f0SSascha Wildner */
120*479ab7f0SSascha Wildner		.set SCR_MAT,0x7		# Mode/attribute
121*479ab7f0SSascha Wildner		.set SCR_COL,0x50		# Columns per row
122*479ab7f0SSascha Wildner		.set SCR_ROW,0x19		# Rows per screen
123*479ab7f0SSascha Wildner
124*479ab7f0SSascha Wildner/*
125*479ab7f0SSascha Wildner * Derivations, for brevity.
126*479ab7f0SSascha Wildner */
127*479ab7f0SSascha Wildner		.set _ESP0H,MEM_BTX_ESP0>>0x8	# Byte 1 of ESP0
128*479ab7f0SSascha Wildner		.set _TSSIO,MEM_BTX_MAP-MEM_BTX_TSS	# TSS I/O base
129*479ab7f0SSascha Wildner		.set _TSSLM,MEM_BTX_TSS_END-MEM_BTX_TSS	# TSS limit
130*479ab7f0SSascha Wildner		.set _IDTLM,MEM_BTX_TSS-MEM_BTX_IDT-1	# IDT limit
131*479ab7f0SSascha Wildner
132*479ab7f0SSascha Wildner/*
133*479ab7f0SSascha Wildner * Code segment.
134*479ab7f0SSascha Wildner *
135*479ab7f0SSascha Wildner * BTX start.
136*479ab7f0SSascha Wildner */
137*479ab7f0SSascha Wildner		.globl start
138*479ab7f0SSascha Wildner		.code16
139*479ab7f0SSascha Wildnerstart:						# Start of code
140*479ab7f0SSascha Wildner
141*479ab7f0SSascha Wildner/*
142*479ab7f0SSascha Wildner * BTX header.
143*479ab7f0SSascha Wildner */
144*479ab7f0SSascha Wildnerbtx_hdr:	.byte 0xeb			# Machine ID
145*479ab7f0SSascha Wildner		.byte 0xe			# Header size
146*479ab7f0SSascha Wildner		.ascii "BTX"			# Magic
147*479ab7f0SSascha Wildner		.byte 0x1			# Major version
148*479ab7f0SSascha Wildner		.byte 0x2			# Minor version
149*479ab7f0SSascha Wildner		.byte BTX_FLAGS			# Flags
150*479ab7f0SSascha Wildner		.word PAG_CNT-MEM_BTX_ORG>>0xc	# Paging control
151*479ab7f0SSascha Wildner		.word break-start		# Text size
152*479ab7f0SSascha Wildner		.long 0x0			# Entry address
153*479ab7f0SSascha Wildner
154*479ab7f0SSascha Wildner/*
155*479ab7f0SSascha Wildner * Initialization routine.
156*479ab7f0SSascha Wildner */
157*479ab7f0SSascha Wildnerinit:		cli				# Disable interrupts
158*479ab7f0SSascha Wildner		xor %ax,%ax			# Zero/segment
159*479ab7f0SSascha Wildner		mov %ax,%ss			# Set up
160*479ab7f0SSascha Wildner		mov $MEM_BTX_ESP0,%sp		#  stack
161*479ab7f0SSascha Wildner		mov %ax,%es			# Address
162*479ab7f0SSascha Wildner		mov %ax,%ds			#  data
163*479ab7f0SSascha Wildner		pushl $0x2			# Clear
164*479ab7f0SSascha Wildner		popfl				#  flags
165*479ab7f0SSascha Wildner
166*479ab7f0SSascha Wildner/*
167*479ab7f0SSascha Wildner * Initialize memory.
168*479ab7f0SSascha Wildner */
169*479ab7f0SSascha Wildner		mov $MEM_BTX_IDT,%di		# Memory to initialize
170*479ab7f0SSascha Wildner		mov $(MEM_BTX_ZEND-MEM_BTX_IDT)/2,%cx	# Words to zero
171*479ab7f0SSascha Wildner		rep				# Zero-fill
172*479ab7f0SSascha Wildner		stosw				#  memory
173*479ab7f0SSascha Wildner
174*479ab7f0SSascha Wildner/*
175*479ab7f0SSascha Wildner * Update real mode IDT for reflecting hardware interrupts.
176*479ab7f0SSascha Wildner */
177*479ab7f0SSascha Wildner		mov $intr20,%bx			# Address first handler
178*479ab7f0SSascha Wildner		mov $0x10,%cx			# Number of handlers
179*479ab7f0SSascha Wildner		mov $0x20*4,%di			# First real mode IDT entry
180*479ab7f0SSascha Wildnerinit.0:		mov %bx,(%di)			# Store IP
181*479ab7f0SSascha Wildner		inc %di				# Address next
182*479ab7f0SSascha Wildner		inc %di				#  entry
183*479ab7f0SSascha Wildner		stosw				# Store CS
184*479ab7f0SSascha Wildner		add $4,%bx			# Next handler
185*479ab7f0SSascha Wildner		loop init.0			# Next IRQ
186*479ab7f0SSascha Wildner/*
187*479ab7f0SSascha Wildner * Create IDT.
188*479ab7f0SSascha Wildner */
189*479ab7f0SSascha Wildner		mov $MEM_BTX_IDT,%di
190*479ab7f0SSascha Wildner		mov $idtctl,%si			# Control string
191*479ab7f0SSascha Wildnerinit.1: 	lodsb				# Get entry
192*479ab7f0SSascha Wildner		cbw				#  count
193*479ab7f0SSascha Wildner		xchg %ax,%cx			#  as word
194*479ab7f0SSascha Wildner		jcxz init.4			# If done
195*479ab7f0SSascha Wildner		lodsb				# Get segment
196*479ab7f0SSascha Wildner		xchg %ax,%dx	 		#  P:DPL:type
197*479ab7f0SSascha Wildner		lodsw				# Get control
198*479ab7f0SSascha Wildner		xchg %ax,%bx			#  set
199*479ab7f0SSascha Wildner		lodsw				# Get handler offset
200*479ab7f0SSascha Wildner		mov $SEL_SCODE,%dh		# Segment selector
201*479ab7f0SSascha Wildnerinit.2: 	shr %bx				# Handle this int?
202*479ab7f0SSascha Wildner		jnc init.3			# No
203*479ab7f0SSascha Wildner		mov %ax,(%di)			# Set handler offset
204*479ab7f0SSascha Wildner		mov %dh,0x2(%di)		#  and selector
205*479ab7f0SSascha Wildner		mov %dl,0x5(%di)		# Set P:DPL:type
206*479ab7f0SSascha Wildner		add $0x4,%ax			# Next handler
207*479ab7f0SSascha Wildnerinit.3: 	lea 0x8(%di),%di		# Next entry
208*479ab7f0SSascha Wildner		loop init.2			# Till set done
209*479ab7f0SSascha Wildner		jmp init.1			# Continue
210*479ab7f0SSascha Wildner
211*479ab7f0SSascha Wildner/*
212*479ab7f0SSascha Wildner * Initialize TSS.
213*479ab7f0SSascha Wildner */
214*479ab7f0SSascha Wildnerinit.4: 	movb $_ESP0H,TSS_ESP0+1(%di)	# Set ESP0
215*479ab7f0SSascha Wildner		movb $SEL_SDATA,TSS_SS0(%di)	# Set SS0
216*479ab7f0SSascha Wildner		movb $_TSSIO,TSS_MAP(%di)	# Set I/O bit map base
217*479ab7f0SSascha Wildner/*
218*479ab7f0SSascha Wildner * Bring up the system.
219*479ab7f0SSascha Wildner */
220*479ab7f0SSascha Wildner		mov $0x2820,%bx			# Set protected mode
221*479ab7f0SSascha Wildner		callw setpic			#  IRQ offsets
222*479ab7f0SSascha Wildner		lidt idtdesc	 		# Set IDT
223*479ab7f0SSascha Wildner		lgdt gdtdesc	 		# Set GDT
224*479ab7f0SSascha Wildner		mov %cr0,%eax			# Switch to protected
225*479ab7f0SSascha Wildner		or $0x01,%eax			#  mode
226*479ab7f0SSascha Wildner		mov %eax,%cr0			#
227*479ab7f0SSascha Wildner		ljmp $SEL_SCODE,$init.8		# To 32-bit code
228*479ab7f0SSascha Wildner		.code32
229*479ab7f0SSascha Wildnerinit.8: 	xorl %ecx,%ecx			# Zero
230*479ab7f0SSascha Wildner		movb $SEL_SDATA,%cl		# To 32-bit
231*479ab7f0SSascha Wildner		movw %cx,%ss			#  stack
232*479ab7f0SSascha Wildner
233*479ab7f0SSascha Wildner/*
234*479ab7f0SSascha Wildner * Launch user task.
235*479ab7f0SSascha Wildner */
236*479ab7f0SSascha Wildner		movb $SEL_TSS,%cl		# Set task
237*479ab7f0SSascha Wildner		ltr %cx				#  register
238*479ab7f0SSascha Wildner
239*479ab7f0SSascha Wildner/*
240*479ab7f0SSascha Wildner * BTX user area base of VM, for converting physical stack
241*479ab7f0SSascha Wildner * addresses to btx-client virtual stack addresses.
242*479ab7f0SSascha Wildner */
243*479ab7f0SSascha Wildner		movl $MEM_BTX_USR,%edx
244*479ab7f0SSascha Wildner#if !defined(MEM_BTX_USR_STK)
245*479ab7f0SSascha Wildner/*
246*479ab7f0SSascha Wildner * XXX We should NOT use BDA_MEM here.  Use a fixed location
247*479ab7f0SSascha Wildner * instead.  (%eax is a physical stack addr)
248*479ab7f0SSascha Wildner *
249*479ab7f0SSascha Wildner * (must match stack specified in btxldr)
250*479ab7f0SSascha Wildner */
251*479ab7f0SSascha Wildner		movzwl %ss:BDA_MEM,%eax 	# Get free memory
252*479ab7f0SSascha Wildner		decl %eax			# Don't quite trust bios
253*479ab7f0SSascha Wildner		shll $0xa,%eax			# To bytes
254*479ab7f0SSascha Wildner#else
255*479ab7f0SSascha Wildner/*
256*479ab7f0SSascha Wildner * Use a fixed user stack instead of depending on BDA_MEM.
257*479ab7f0SSascha Wildner * %eax is a physical * stack address.
258*479ab7f0SSascha Wildner */
259*479ab7f0SSascha Wildner		movl $MEM_BTX_USR_STK,%eax
260*479ab7f0SSascha Wildner#endif
261*479ab7f0SSascha Wildner		subl $USR_ARGSPACE,%eax		# Less arg space
262*479ab7f0SSascha Wildner		subl %edx,%eax			# Less base Phys->Virt
263*479ab7f0SSascha Wildner		movb $SEL_UDATA,%cl		# User data selector
264*479ab7f0SSascha Wildner		pushl %ecx			# Set SS
265*479ab7f0SSascha Wildner		pushl %eax			# Set ESP (virtual address)
266*479ab7f0SSascha Wildner		push $0x202			# Set flags (IF set)
267*479ab7f0SSascha Wildner		push $SEL_UCODE			# Set CS
268*479ab7f0SSascha Wildner		pushl btx_hdr+0xc		# Set EIP
269*479ab7f0SSascha Wildner		pushl %ecx			# Set GS
270*479ab7f0SSascha Wildner		pushl %ecx			# Set FS
271*479ab7f0SSascha Wildner		pushl %ecx			# Set DS
272*479ab7f0SSascha Wildner		pushl %ecx			# Set ES
273*479ab7f0SSascha Wildner		pushl %edx			# Set EAX (phys base addr of VM)
274*479ab7f0SSascha Wildner		movb $0x7,%cl			# Set remaining
275*479ab7f0SSascha Wildnerinit.9:		push $0x0			#  general
276*479ab7f0SSascha Wildner		loop init.9			#  registers
277*479ab7f0SSascha Wildner#ifdef BTX_SERIAL
278*479ab7f0SSascha Wildner		call sio_init			# setup the serial console
279*479ab7f0SSascha Wildner#endif
280*479ab7f0SSascha Wildner		popa				#  and initialize
281*479ab7f0SSascha Wildner		popl %es			# Initialize
282*479ab7f0SSascha Wildner		popl %ds			#  user
283*479ab7f0SSascha Wildner		popl %fs			#  segment
284*479ab7f0SSascha Wildner		popl %gs			#  registers
285*479ab7f0SSascha Wildner		iret				# To user mode
286*479ab7f0SSascha Wildner
287*479ab7f0SSascha Wildner/*
288*479ab7f0SSascha Wildner * Exit routine.
289*479ab7f0SSascha Wildner */
290*479ab7f0SSascha Wildnerexit:		cli				# Disable interrupts
291*479ab7f0SSascha Wildner		movl $MEM_BTX_ESP0,%esp		# Clear stack
292*479ab7f0SSascha Wildner
293*479ab7f0SSascha Wildner/*
294*479ab7f0SSascha Wildner * Turn off paging.
295*479ab7f0SSascha Wildner */
296*479ab7f0SSascha Wildner		movl %cr0,%eax			# Get CR0
297*479ab7f0SSascha Wildner		andl $~0x80000000,%eax		# Disable
298*479ab7f0SSascha Wildner		movl %eax,%cr0			#  paging
299*479ab7f0SSascha Wildner		xorl %ecx,%ecx			# Zero
300*479ab7f0SSascha Wildner		movl %ecx,%cr3			# Flush TLB
301*479ab7f0SSascha Wildner
302*479ab7f0SSascha Wildner/*
303*479ab7f0SSascha Wildner * Restore the GDT in case we caught a kernel trap.
304*479ab7f0SSascha Wildner */
305*479ab7f0SSascha Wildner		lgdt %cs:gdtdesc	 	# Set GDT
306*479ab7f0SSascha Wildner
307*479ab7f0SSascha Wildner/*
308*479ab7f0SSascha Wildner * To 16 bits.
309*479ab7f0SSascha Wildner */
310*479ab7f0SSascha Wildner		ljmpw $SEL_RCODE,$exit.1	# Reload CS
311*479ab7f0SSascha Wildner		.code16
312*479ab7f0SSascha Wildnerexit.1: 	mov $SEL_RDATA,%cl		# 16-bit selector
313*479ab7f0SSascha Wildner		mov %cx,%ss			# Reload SS
314*479ab7f0SSascha Wildner		mov %cx,%ds			# Load
315*479ab7f0SSascha Wildner		mov %cx,%es			#  remaining
316*479ab7f0SSascha Wildner		mov %cx,%fs			#  segment
317*479ab7f0SSascha Wildner		mov %cx,%gs			#  registers
318*479ab7f0SSascha Wildner
319*479ab7f0SSascha Wildner/*
320*479ab7f0SSascha Wildner * To real-address mode.
321*479ab7f0SSascha Wildner */
322*479ab7f0SSascha Wildner		dec %ax				# Switch to
323*479ab7f0SSascha Wildner		mov %eax,%cr0			#  real mode
324*479ab7f0SSascha Wildner		ljmp $0x0,$exit.2		# Reload CS
325*479ab7f0SSascha Wildnerexit.2: 	xor %ax,%ax			# Real mode segment
326*479ab7f0SSascha Wildner		mov %ax,%ss			# Reload SS
327*479ab7f0SSascha Wildner		mov %ax,%ds			# Address data
328*479ab7f0SSascha Wildner		mov $0x7008,%bx			# Set real mode
329*479ab7f0SSascha Wildner		callw setpic			#  IRQ offsets
330*479ab7f0SSascha Wildner		lidt ivtdesc	 		# Set IVT
331*479ab7f0SSascha Wildner
332*479ab7f0SSascha Wildner/*
333*479ab7f0SSascha Wildner * Reboot or await reset.
334*479ab7f0SSascha Wildner */
335*479ab7f0SSascha Wildner		sti				# Enable interrupts
336*479ab7f0SSascha Wildner		testb $0x1,btx_hdr+0x7		# Reboot?
337*479ab7f0SSascha Wildnerexit.3:		jz exit.3			# No
338*479ab7f0SSascha Wildner		movw $0x1234, BDA_BOOT		# Do a warm boot
339*479ab7f0SSascha Wildner		ljmp $0xf000,$0xfff0		# reboot the machine
340*479ab7f0SSascha Wildner
341*479ab7f0SSascha Wildner/*
342*479ab7f0SSascha Wildner * Set IRQ offsets by reprogramming 8259A PICs.
343*479ab7f0SSascha Wildner */
344*479ab7f0SSascha Wildnersetpic: 	in $0x21,%al			# Save master
345*479ab7f0SSascha Wildner		push %ax			#  IMR
346*479ab7f0SSascha Wildner		in $0xa1,%al			# Save slave
347*479ab7f0SSascha Wildner		push %ax			#  IMR
348*479ab7f0SSascha Wildner		movb $0x11,%al			# ICW1 to
349*479ab7f0SSascha Wildner		outb %al,$0x20			#  master,
350*479ab7f0SSascha Wildner		outb %al,$0xa0			#  slave
351*479ab7f0SSascha Wildner		movb %bl,%al			# ICW2 to
352*479ab7f0SSascha Wildner		outb %al,$0x21			#  master
353*479ab7f0SSascha Wildner		movb %bh,%al			# ICW2 to
354*479ab7f0SSascha Wildner		outb %al,$0xa1			#  slave
355*479ab7f0SSascha Wildner		movb $0x4,%al			# ICW3 to
356*479ab7f0SSascha Wildner		outb %al,$0x21			#  master
357*479ab7f0SSascha Wildner		movb $0x2,%al			# ICW3 to
358*479ab7f0SSascha Wildner		outb %al,$0xa1			#  slave
359*479ab7f0SSascha Wildner		movb $0x1,%al			# ICW4 to
360*479ab7f0SSascha Wildner		outb %al,$0x21			#  master,
361*479ab7f0SSascha Wildner		outb %al,$0xa1			#  slave
362*479ab7f0SSascha Wildner		pop %ax				# Restore slave
363*479ab7f0SSascha Wildner		outb %al,$0xa1			#  IMR
364*479ab7f0SSascha Wildner		pop %ax				# Restore master
365*479ab7f0SSascha Wildner		outb %al,$0x21			#  IMR
366*479ab7f0SSascha Wildner		retw				# To caller
367*479ab7f0SSascha Wildner		.code32
368*479ab7f0SSascha Wildner
369*479ab7f0SSascha Wildner/*
370*479ab7f0SSascha Wildner * Exception jump table.
371*479ab7f0SSascha Wildner */
372*479ab7f0SSascha Wildnerintx00: 	push $0x0			# Int 0x0: #DE
373*479ab7f0SSascha Wildner		jmp ex_noc			# Divide error
374*479ab7f0SSascha Wildner		push $0x1			# Int 0x1: #DB
375*479ab7f0SSascha Wildner		jmp ex_noc			# Debug
376*479ab7f0SSascha Wildner		push $0x3			# Int 0x3: #BP
377*479ab7f0SSascha Wildner		jmp ex_noc			# Breakpoint
378*479ab7f0SSascha Wildner		push $0x4			# Int 0x4: #OF
379*479ab7f0SSascha Wildner		jmp ex_noc			# Overflow
380*479ab7f0SSascha Wildner		push $0x5			# Int 0x5: #BR
381*479ab7f0SSascha Wildner		jmp ex_noc			# BOUND range exceeded
382*479ab7f0SSascha Wildner		push $0x6			# Int 0x6: #UD
383*479ab7f0SSascha Wildner		jmp ex_noc			# Invalid opcode
384*479ab7f0SSascha Wildner		push $0x7			# Int 0x7: #NM
385*479ab7f0SSascha Wildner		jmp ex_noc			# Device not available
386*479ab7f0SSascha Wildner		push $0x8			# Int 0x8: #DF
387*479ab7f0SSascha Wildner		jmp except			# Double fault
388*479ab7f0SSascha Wildner		push $0xa			# Int 0xa: #TS
389*479ab7f0SSascha Wildner		jmp except			# Invalid TSS
390*479ab7f0SSascha Wildner		push $0xb			# Int 0xb: #NP
391*479ab7f0SSascha Wildner		jmp except			# Segment not present
392*479ab7f0SSascha Wildner		push $0xc			# Int 0xc: #SS
393*479ab7f0SSascha Wildner		jmp except			# Stack segment fault
394*479ab7f0SSascha Wildner		push $0xd			# Int 0xd: #GP
395*479ab7f0SSascha Wildner		jmp except			# General protection
396*479ab7f0SSascha Wildner		push $0xe			# Int 0xe: #PF
397*479ab7f0SSascha Wildner		jmp except			# Page fault
398*479ab7f0SSascha Wildnerintx10: 	push $0x10			# Int 0x10: #MF
399*479ab7f0SSascha Wildner		jmp ex_noc			# Floating-point error
400*479ab7f0SSascha Wildner
401*479ab7f0SSascha Wildner/*
402*479ab7f0SSascha Wildner * Save a zero error code.
403*479ab7f0SSascha Wildner */
404*479ab7f0SSascha Wildnerex_noc: 	pushl (%esp,1)			# Duplicate int no
405*479ab7f0SSascha Wildner		movb $0x0,0x4(%esp,1)		# Fake error code
406*479ab7f0SSascha Wildner
407*479ab7f0SSascha Wildner/*
408*479ab7f0SSascha Wildner * Handle exception.
409*479ab7f0SSascha Wildner */
410*479ab7f0SSascha Wildnerexcept: 	cld				# String ops inc
411*479ab7f0SSascha Wildner		pushl %ds			# Save
412*479ab7f0SSascha Wildner		pushl %es			#  most
413*479ab7f0SSascha Wildner		pusha				#  registers
414*479ab7f0SSascha Wildner		pushl %gs			# Set GS
415*479ab7f0SSascha Wildner		pushl %fs			# Set FS
416*479ab7f0SSascha Wildner		pushl %ds			# Set DS
417*479ab7f0SSascha Wildner		pushl %es			# Set ES
418*479ab7f0SSascha Wildner		cmpw $SEL_SCODE,0x44(%esp,1)	# Supervisor mode?
419*479ab7f0SSascha Wildner		jne except.1			# No
420*479ab7f0SSascha Wildner		pushl %ss			# Set SS
421*479ab7f0SSascha Wildner		jmp except.2			# Join common code
422*479ab7f0SSascha Wildnerexcept.1:	pushl 0x50(%esp,1)		# Set SS
423*479ab7f0SSascha Wildnerexcept.2:	pushl 0x50(%esp,1)		# Set ESP
424*479ab7f0SSascha Wildner		push $SEL_SDATA			# Set up
425*479ab7f0SSascha Wildner		popl %ds			#  to
426*479ab7f0SSascha Wildner		pushl %ds			#  address
427*479ab7f0SSascha Wildner		popl %es			#  data
428*479ab7f0SSascha Wildner		movl %esp,%ebx			# Stack frame
429*479ab7f0SSascha Wildner		movl $dmpfmt,%esi		# Dump format string
430*479ab7f0SSascha Wildner		movl $MEM_BTX_BUF,%edi		# Buffer
431*479ab7f0SSascha Wildner		pushl %edi			# Dump to
432*479ab7f0SSascha Wildner		call dump			#  buffer
433*479ab7f0SSascha Wildner		popl %esi			#  and
434*479ab7f0SSascha Wildner		call putstr			#  display
435*479ab7f0SSascha Wildner		leal 0x18(%esp,1),%esp		# Discard frame
436*479ab7f0SSascha Wildner		popa				# Restore
437*479ab7f0SSascha Wildner		popl %es			#  registers
438*479ab7f0SSascha Wildner		popl %ds			#  saved
439*479ab7f0SSascha Wildner		cmpb $0x3,(%esp,1)		# Breakpoint?
440*479ab7f0SSascha Wildner		je except.3			# Yes
441*479ab7f0SSascha Wildner		cmpb $0x1,(%esp,1)		# Debug?
442*479ab7f0SSascha Wildner		jne except.2a			# No
443*479ab7f0SSascha Wildner		testl $PSL_T,0x10(%esp,1)	# Trap flag set?
444*479ab7f0SSascha Wildner		jnz except.3			# Yes
445*479ab7f0SSascha Wildnerexcept.2a:	jmp exit			# Exit
446*479ab7f0SSascha Wildnerexcept.3:	leal 0x8(%esp,1),%esp		# Discard err, int no
447*479ab7f0SSascha Wildner		iret				# From interrupt
448*479ab7f0SSascha Wildner
449*479ab7f0SSascha Wildner/*
450*479ab7f0SSascha Wildner * Reboot the machine by setting the reboot flag and exiting
451*479ab7f0SSascha Wildner */
452*479ab7f0SSascha Wildnerreboot:		orb $0x1,btx_hdr+0x7		# Set the reboot flag
453*479ab7f0SSascha Wildner		jmp exit			# Terminate BTX and reboot
454*479ab7f0SSascha Wildner
455*479ab7f0SSascha Wildner/*
456*479ab7f0SSascha Wildner * Protected Mode Hardware interrupt jump table.
457*479ab7f0SSascha Wildner */
458*479ab7f0SSascha Wildnerintx20: 	push $0x8			# Int 0x20: IRQ0
459*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0x8
460*479ab7f0SSascha Wildner		push $0x9			# Int 0x21: IRQ1
461*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0x9
462*479ab7f0SSascha Wildner		push $0xa			# Int 0x22: IRQ2
463*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0xa
464*479ab7f0SSascha Wildner		push $0xb			# Int 0x23: IRQ3
465*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0xb
466*479ab7f0SSascha Wildner		push $0xc			# Int 0x24: IRQ4
467*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0xc
468*479ab7f0SSascha Wildner		push $0xd			# Int 0x25: IRQ5
469*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0xd
470*479ab7f0SSascha Wildner		push $0xe			# Int 0x26: IRQ6
471*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0xe
472*479ab7f0SSascha Wildner		push $0xf			# Int 0x27: IRQ7
473*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0xf
474*479ab7f0SSascha Wildner		push $0x70			# Int 0x28: IRQ8
475*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0x70
476*479ab7f0SSascha Wildner		push $0x71			# Int 0x29: IRQ9
477*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0x71
478*479ab7f0SSascha Wildner		push $0x72			# Int 0x2a: IRQ10
479*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0x72
480*479ab7f0SSascha Wildner		push $0x73			# Int 0x2b: IRQ11
481*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0x73
482*479ab7f0SSascha Wildner		push $0x74			# Int 0x2c: IRQ12
483*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0x74
484*479ab7f0SSascha Wildner		push $0x75			# Int 0x2d: IRQ13
485*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0x75
486*479ab7f0SSascha Wildner		push $0x76			# Int 0x2e: IRQ14
487*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0x76
488*479ab7f0SSascha Wildner		push $0x77			# Int 0x2f: IRQ15
489*479ab7f0SSascha Wildner		jmp int_hw			# V86 int 0x77
490*479ab7f0SSascha Wildner
491*479ab7f0SSascha Wildner/*
492*479ab7f0SSascha Wildner * Invoke real mode interrupt/function call from user mode with arguments.
493*479ab7f0SSascha Wildner */
494*479ab7f0SSascha Wildnerintx31: 	pushl $-1			# Dummy int no for btx_v86
495*479ab7f0SSascha Wildner
496*479ab7f0SSascha Wildner/*
497*479ab7f0SSascha Wildner * Invoke real mode interrupt/function call from protected mode.
498*479ab7f0SSascha Wildner *
499*479ab7f0SSascha Wildner * We place a trampoline on the user stack that will return to rret_tramp
500*479ab7f0SSascha Wildner * which will reenter protected mode and then finally return to the user
501*479ab7f0SSascha Wildner * client.
502*479ab7f0SSascha Wildner *
503*479ab7f0SSascha Wildner * Kernel frame %esi points to:		Real mode stack frame at MEM_BTX_ESPR:
504*479ab7f0SSascha Wildner *
505*479ab7f0SSascha Wildner * -0x00 user %ss			-0x04 kernel %esp (with full frame)
506*479ab7f0SSascha Wildner * -0x04 user %esp			-0x08 btx_v86 pointer
507*479ab7f0SSascha Wildner * -0x08 user %eflags			-0x0c flags (only used if interrupt)
508*479ab7f0SSascha Wildner * -0x0c user %cs			-0x10 real mode CS:IP return trampoline
509*479ab7f0SSascha Wildner * -0x10 user %eip			-0x12 real mode flags
510*479ab7f0SSascha Wildner * -0x14 int no				-0x16 real mode CS:IP (target)
511*479ab7f0SSascha Wildner * -0x18 %eax
512*479ab7f0SSascha Wildner * -0x1c %ecx
513*479ab7f0SSascha Wildner * -0x20 %edx
514*479ab7f0SSascha Wildner * -0x24 %ebx
515*479ab7f0SSascha Wildner * -0x28 %esp
516*479ab7f0SSascha Wildner * -0x2c %ebp
517*479ab7f0SSascha Wildner * -0x30 %esi
518*479ab7f0SSascha Wildner * -0x34 %edi
519*479ab7f0SSascha Wildner * -0x38 %gs
520*479ab7f0SSascha Wildner * -0x3c %fs
521*479ab7f0SSascha Wildner * -0x40 %ds
522*479ab7f0SSascha Wildner * -0x44 %es
523*479ab7f0SSascha Wildner * -0x48 zero %eax (hardware int only)
524*479ab7f0SSascha Wildner * -0x4c zero %ecx (hardware int only)
525*479ab7f0SSascha Wildner * -0x50 zero %edx (hardware int only)
526*479ab7f0SSascha Wildner * -0x54 zero %ebx (hardware int only)
527*479ab7f0SSascha Wildner * -0x58 zero %esp (hardware int only)
528*479ab7f0SSascha Wildner * -0x5c zero %ebp (hardware int only)
529*479ab7f0SSascha Wildner * -0x60 zero %esi (hardware int only)
530*479ab7f0SSascha Wildner * -0x64 zero %edi (hardware int only)
531*479ab7f0SSascha Wildner * -0x68 zero %gs (hardware int only)
532*479ab7f0SSascha Wildner * -0x6c zero %fs (hardware int only)
533*479ab7f0SSascha Wildner * -0x70 zero %ds (hardware int only)
534*479ab7f0SSascha Wildner * -0x74 zero %es (hardware int only)
535*479ab7f0SSascha Wildner */
536*479ab7f0SSascha Wildnerint_hw: 	cld				# String ops inc
537*479ab7f0SSascha Wildner		pusha				# Save gp regs
538*479ab7f0SSascha Wildner		pushl %gs			# Save
539*479ab7f0SSascha Wildner		pushl %fs			#  seg
540*479ab7f0SSascha Wildner		pushl %ds			#  regs
541*479ab7f0SSascha Wildner		pushl %es
542*479ab7f0SSascha Wildner		push $SEL_SDATA			# Set up
543*479ab7f0SSascha Wildner		popl %ds			#  to
544*479ab7f0SSascha Wildner		pushl %ds			#  address
545*479ab7f0SSascha Wildner		popl %es			#  data
546*479ab7f0SSascha Wildner		leal 0x44(%esp,1),%esi		# Base of frame
547*479ab7f0SSascha Wildner		movl %esp,MEM_BTX_ESPR-0x04		# Save kernel stack pointer
548*479ab7f0SSascha Wildner		movl -0x14(%esi),%eax		# Get Int no
549*479ab7f0SSascha Wildner		cmpl $-1,%eax			# Hardware interrupt?
550*479ab7f0SSascha Wildner		jne intusr.1			# Yes
551*479ab7f0SSascha Wildner/*
552*479ab7f0SSascha Wildner * v86 calls save the btx_v86 pointer on the real mode stack and read
553*479ab7f0SSascha Wildner * the address and flags from the btx_v86 structure.  For interrupt
554*479ab7f0SSascha Wildner * handler invocations (VM86 INTx requests), disable interrupts,
555*479ab7f0SSascha Wildner * tracing, and alignment checking while the handler runs.
556*479ab7f0SSascha Wildner */
557*479ab7f0SSascha Wildner		movl $MEM_BTX_USR,%ebx		# User base
558*479ab7f0SSascha Wildner		movl %ebx,%edx			#  address
559*479ab7f0SSascha Wildner		addl -0x4(%esi),%ebx		# User ESP
560*479ab7f0SSascha Wildner		movl (%ebx),%ebp		# btx_v86 pointer
561*479ab7f0SSascha Wildner		addl %ebp,%edx			# Flatten btx_v86 ptr
562*479ab7f0SSascha Wildner		movl %edx,MEM_BTX_ESPR-0x08		# Save btx_v86 ptr
563*479ab7f0SSascha Wildner		movl V86_ADDR(%edx),%eax	# Get int no/address
564*479ab7f0SSascha Wildner		movl V86_CTL(%edx),%edx		# Get control flags
565*479ab7f0SSascha Wildner		movl -0x08(%esi),%ebx		# Save user flags in %ebx
566*479ab7f0SSascha Wildner		testl $V86F_ADDR,%edx		# Segment:offset?
567*479ab7f0SSascha Wildner		jnz intusr.4			# Yes
568*479ab7f0SSascha Wildner		andl $~(PSL_I|PSL_T|PSL_AC),%ebx # Disable interrupts, tracing,
569*479ab7f0SSascha Wildner						#  and alignment checking for
570*479ab7f0SSascha Wildner						#  interrupt handler
571*479ab7f0SSascha Wildner		jmp intusr.3			# Skip hardware interrupt
572*479ab7f0SSascha Wildner/*
573*479ab7f0SSascha Wildner * Hardware interrupts store a NULL btx_v86 pointer and use the
574*479ab7f0SSascha Wildner * address (interrupt number) from the stack with empty flags.  Also,
575*479ab7f0SSascha Wildner * push a dummy frame of zeros onto the stack for all the general
576*479ab7f0SSascha Wildner * purpose and segment registers and clear %eflags.  This gives the
577*479ab7f0SSascha Wildner * hardware interrupt handler a clean slate.
578*479ab7f0SSascha Wildner */
579*479ab7f0SSascha Wildnerintusr.1:	xorl %edx,%edx			# Control flags
580*479ab7f0SSascha Wildner		movl %edx,MEM_BTX_ESPR-0x08		# NULL btx_v86 ptr
581*479ab7f0SSascha Wildner		movl $12,%ecx			# Frame is 12 dwords
582*479ab7f0SSascha Wildnerintusr.2:	pushl $0x0			# Fill frame
583*479ab7f0SSascha Wildner		loop intusr.2			#  with zeros
584*479ab7f0SSascha Wildner		movl $PSL_RESERVED_DEFAULT,%ebx # Set clean %eflags
585*479ab7f0SSascha Wildner/*
586*479ab7f0SSascha Wildner * Look up real mode IDT entry for hardware interrupts and VM86 INTx
587*479ab7f0SSascha Wildner * requests.
588*479ab7f0SSascha Wildner */
589*479ab7f0SSascha Wildnerintusr.3:	shll $0x2,%eax			# Scale
590*479ab7f0SSascha Wildner		movl (%eax),%eax		# Load int vector
591*479ab7f0SSascha Wildner		jmp intusr.5			# Skip CALLF test
592*479ab7f0SSascha Wildner/*
593*479ab7f0SSascha Wildner * Panic if V86F_CALLF isn't set with V86F_ADDR.
594*479ab7f0SSascha Wildner */
595*479ab7f0SSascha Wildnerintusr.4:	testl $V86F_CALLF,%edx		# Far call?
596*479ab7f0SSascha Wildner		jnz intusr.5			# Ok
597*479ab7f0SSascha Wildner		movl %edx,0x30(%esp,1)		# Place VM86 flags in int no
598*479ab7f0SSascha Wildner		movl $badvm86,%esi		# Display bad
599*479ab7f0SSascha Wildner		call putstr			#  VM86 call
600*479ab7f0SSascha Wildner		popl %es			# Restore
601*479ab7f0SSascha Wildner		popl %ds			#  seg
602*479ab7f0SSascha Wildner		popl %fs			#  regs
603*479ab7f0SSascha Wildner		popl %gs
604*479ab7f0SSascha Wildner		popal				# Restore gp regs
605*479ab7f0SSascha Wildner		jmp ex_noc			# Panic
606*479ab7f0SSascha Wildner/*
607*479ab7f0SSascha Wildner * %eax now holds the segment:offset of the function.
608*479ab7f0SSascha Wildner * %ebx now holds the %eflags to pass to real mode.
609*479ab7f0SSascha Wildner * %edx now holds the V86F_* flags.
610*479ab7f0SSascha Wildner */
611*479ab7f0SSascha Wildnerintusr.5:	movw %bx,MEM_BTX_ESPR-0x12		# Pass user flags to real mode
612*479ab7f0SSascha Wildner						#  target
613*479ab7f0SSascha Wildner/*
614*479ab7f0SSascha Wildner * If this is a v86 call, copy the seg regs out of the btx_v86 structure.
615*479ab7f0SSascha Wildner */
616*479ab7f0SSascha Wildner		movl MEM_BTX_ESPR-0x08,%ecx		# Get btx_v86 ptr
617*479ab7f0SSascha Wildner		jecxz intusr.6			# Skip for hardware ints
618*479ab7f0SSascha Wildner		leal -0x44(%esi),%edi		# %edi => kernel stack seg regs
619*479ab7f0SSascha Wildner		pushl %esi			# Save
620*479ab7f0SSascha Wildner		leal V86_ES(%ecx),%esi		# %esi => btx_v86 seg regs
621*479ab7f0SSascha Wildner		movl $4,%ecx			# Copy seg regs
622*479ab7f0SSascha Wildner		rep				#  from btx_v86
623*479ab7f0SSascha Wildner		movsl				#  to kernel stack
624*479ab7f0SSascha Wildner		popl %esi			# Restore
625*479ab7f0SSascha Wildnerintusr.6:	movl -0x08(%esi),%ebx		# Copy user flags to real
626*479ab7f0SSascha Wildner		movl %ebx,MEM_BTX_ESPR-0x0c		#  mode return trampoline
627*479ab7f0SSascha Wildner		movl $rret_tramp,%ebx		# Set return trampoline
628*479ab7f0SSascha Wildner		movl %ebx,MEM_BTX_ESPR-0x10		#  CS:IP
629*479ab7f0SSascha Wildner		movl %eax,MEM_BTX_ESPR-0x16		# Real mode target CS:IP
630*479ab7f0SSascha Wildner		ljmpw $SEL_RCODE,$intusr.7	# Change to 16-bit segment
631*479ab7f0SSascha Wildner		.code16
632*479ab7f0SSascha Wildnerintusr.7:	movl %cr0,%eax			# Leave
633*479ab7f0SSascha Wildner		dec %al				#  protected
634*479ab7f0SSascha Wildner		movl %eax,%cr0			#  mode
635*479ab7f0SSascha Wildner		ljmpw $0x0,$intusr.8
636*479ab7f0SSascha Wildnerintusr.8:	xorw %ax,%ax			# Reset %ds
637*479ab7f0SSascha Wildner		movw %ax,%ds			#  and
638*479ab7f0SSascha Wildner		movw %ax,%ss			#  %ss
639*479ab7f0SSascha Wildner		lidt ivtdesc	 		# Set IVT
640*479ab7f0SSascha Wildner		popl %es			# Restore
641*479ab7f0SSascha Wildner		popl %ds			#  seg
642*479ab7f0SSascha Wildner		popl %fs			#  regs
643*479ab7f0SSascha Wildner		popl %gs
644*479ab7f0SSascha Wildner		popal				# Restore gp regs
645*479ab7f0SSascha Wildner		movw $MEM_BTX_ESPR-0x16,%sp		# Switch to real mode stack
646*479ab7f0SSascha Wildner		iret				# Call target routine
647*479ab7f0SSascha Wildner/*
648*479ab7f0SSascha Wildner * For the return to real mode we setup a stack frame like this on the real
649*479ab7f0SSascha Wildner * mode stack.  Note that callf calls won't pop off the flags, but we just
650*479ab7f0SSascha Wildner * ignore that by repositioning %sp to be just above the btx_v86 pointer
651*479ab7f0SSascha Wildner * so it is aligned.  The stack is relative to MEM_BTX_ESPR.
652*479ab7f0SSascha Wildner *
653*479ab7f0SSascha Wildner * -0x04	kernel %esp
654*479ab7f0SSascha Wildner * -0x08	btx_v86
655*479ab7f0SSascha Wildner * -0x0c	%eax
656*479ab7f0SSascha Wildner * -0x10	%ecx
657*479ab7f0SSascha Wildner * -0x14	%edx
658*479ab7f0SSascha Wildner * -0x18	%ebx
659*479ab7f0SSascha Wildner * -0x1c	%esp
660*479ab7f0SSascha Wildner * -0x20	%ebp
661*479ab7f0SSascha Wildner * -0x24	%esi
662*479ab7f0SSascha Wildner * -0x28	%edi
663*479ab7f0SSascha Wildner * -0x2c	%gs
664*479ab7f0SSascha Wildner * -0x30	%fs
665*479ab7f0SSascha Wildner * -0x34	%ds
666*479ab7f0SSascha Wildner * -0x38	%es
667*479ab7f0SSascha Wildner * -0x3c	%eflags
668*479ab7f0SSascha Wildner */
669*479ab7f0SSascha Wildnerrret_tramp:	movw $MEM_BTX_ESPR-0x08,%sp		# Reset stack pointer
670*479ab7f0SSascha Wildner		pushal				# Save gp regs
671*479ab7f0SSascha Wildner		pushl %gs			# Save
672*479ab7f0SSascha Wildner		pushl %fs			#  seg
673*479ab7f0SSascha Wildner		pushl %ds			#  regs
674*479ab7f0SSascha Wildner		pushl %es
675*479ab7f0SSascha Wildner		pushfl				# Save %eflags
676*479ab7f0SSascha Wildner		pushl $PSL_RESERVED_DEFAULT|PSL_D # Use clean %eflags with
677*479ab7f0SSascha Wildner		popfl				#  string ops dec
678*479ab7f0SSascha Wildner		xorw %ax,%ax			# Reset seg
679*479ab7f0SSascha Wildner		movw %ax,%ds			#  regs
680*479ab7f0SSascha Wildner		movw %ax,%es			#  (%ss is already 0)
681*479ab7f0SSascha Wildner		lidt idtdesc	 		# Set IDT
682*479ab7f0SSascha Wildner		lgdt gdtdesc	 		# Set GDT
683*479ab7f0SSascha Wildner		mov %cr0,%eax			# Switch to protected
684*479ab7f0SSascha Wildner		inc %ax				#  mode
685*479ab7f0SSascha Wildner		mov %eax,%cr0			#
686*479ab7f0SSascha Wildner		ljmp $SEL_SCODE,$rret_tramp.1	# To 32-bit code
687*479ab7f0SSascha Wildner		.code32
688*479ab7f0SSascha Wildnerrret_tramp.1:	xorl %ecx,%ecx			# Zero
689*479ab7f0SSascha Wildner		movb $SEL_SDATA,%cl		# Setup
690*479ab7f0SSascha Wildner		movw %cx,%ss			#  32-bit
691*479ab7f0SSascha Wildner		movw %cx,%ds			#  seg
692*479ab7f0SSascha Wildner		movw %cx,%es			#  regs
693*479ab7f0SSascha Wildner		movl MEM_BTX_ESPR-0x04,%esp		# Switch to kernel stack
694*479ab7f0SSascha Wildner		leal 0x44(%esp,1),%esi		# Base of frame
695*479ab7f0SSascha Wildner		andb $~0x2,tss_desc+0x5		# Clear TSS busy
696*479ab7f0SSascha Wildner		movb $SEL_TSS,%cl		# Set task
697*479ab7f0SSascha Wildner		ltr %cx				#  register
698*479ab7f0SSascha Wildner/*
699*479ab7f0SSascha Wildner * Now we are back in protected mode.  The kernel stack frame set up
700*479ab7f0SSascha Wildner * before entering real mode is still intact. For hardware interrupts,
701*479ab7f0SSascha Wildner * leave the frame unchanged.
702*479ab7f0SSascha Wildner */
703*479ab7f0SSascha Wildner		cmpl $0,MEM_BTX_ESPR-0x08		# Leave saved regs unchanged
704*479ab7f0SSascha Wildner		jz rret_tramp.3			#  for hardware ints
705*479ab7f0SSascha Wildner/*
706*479ab7f0SSascha Wildner * For V86 calls, copy the registers off of the real mode stack onto
707*479ab7f0SSascha Wildner * the kernel stack as we want their updated values.  Also, initialize
708*479ab7f0SSascha Wildner * the segment registers on the kernel stack.
709*479ab7f0SSascha Wildner *
710*479ab7f0SSascha Wildner * Note that the %esp in the kernel stack after this is garbage, but popa
711*479ab7f0SSascha Wildner * ignores it, so we don't have to fix it up.
712*479ab7f0SSascha Wildner */
713*479ab7f0SSascha Wildner		leal -0x18(%esi),%edi		# Kernel stack GP regs
714*479ab7f0SSascha Wildner		pushl %esi			# Save
715*479ab7f0SSascha Wildner		movl $MEM_BTX_ESPR-0x0c,%esi	# Real mode stack GP regs
716*479ab7f0SSascha Wildner		movl $8,%ecx			# Copy GP regs from
717*479ab7f0SSascha Wildner		rep				#  real mode stack
718*479ab7f0SSascha Wildner		movsl				#  to kernel stack
719*479ab7f0SSascha Wildner		movl $SEL_UDATA,%eax		# Selector for data seg regs
720*479ab7f0SSascha Wildner		movl $4,%ecx			# Initialize %ds,
721*479ab7f0SSascha Wildner		rep				#  %es, %fs, and
722*479ab7f0SSascha Wildner		stosl				#  %gs
723*479ab7f0SSascha Wildner/*
724*479ab7f0SSascha Wildner * For V86 calls, copy the saved seg regs on the real mode stack back
725*479ab7f0SSascha Wildner * over to the btx_v86 structure.  Also, conditionally update the
726*479ab7f0SSascha Wildner * saved eflags on the kernel stack based on the flags from the user.
727*479ab7f0SSascha Wildner */
728*479ab7f0SSascha Wildner		movl MEM_BTX_ESPR-0x08,%ecx		# Get btx_v86 ptr
729*479ab7f0SSascha Wildner		leal V86_GS(%ecx),%edi		# %edi => btx_v86 seg regs
730*479ab7f0SSascha Wildner		leal MEM_BTX_ESPR-0x2c,%esi		# %esi => real mode seg regs
731*479ab7f0SSascha Wildner		xchgl %ecx,%edx			# Save btx_v86 ptr
732*479ab7f0SSascha Wildner		movl $4,%ecx			# Copy seg regs
733*479ab7f0SSascha Wildner		rep				#  from real mode stack
734*479ab7f0SSascha Wildner		movsl				#  to btx_v86
735*479ab7f0SSascha Wildner		popl %esi			# Restore
736*479ab7f0SSascha Wildner		movl V86_CTL(%edx),%edx		# Read V86 control flags
737*479ab7f0SSascha Wildner		testl $V86F_FLAGS,%edx		# User wants flags?
738*479ab7f0SSascha Wildner		jz rret_tramp.3			# No
739*479ab7f0SSascha Wildner		movl MEM_BTX_ESPR-0x3c,%eax	# Read real mode flags
740*479ab7f0SSascha Wildner		andl $~(PSL_T|PSL_NT),%eax	# Clear unsafe flags
741*479ab7f0SSascha Wildner		movw %ax,-0x08(%esi)		# Update user flags (low 16)
742*479ab7f0SSascha Wildner/*
743*479ab7f0SSascha Wildner * Return to the user task
744*479ab7f0SSascha Wildner */
745*479ab7f0SSascha Wildnerrret_tramp.3:	popl %es			# Restore
746*479ab7f0SSascha Wildner		popl %ds			#  seg
747*479ab7f0SSascha Wildner		popl %fs			#  regs
748*479ab7f0SSascha Wildner		popl %gs
749*479ab7f0SSascha Wildner		popal				# Restore gp regs
750*479ab7f0SSascha Wildner		addl $4,%esp			# Discard int no
751*479ab7f0SSascha Wildner		iret				# Return to user mode
752*479ab7f0SSascha Wildner
753*479ab7f0SSascha Wildner/*
754*479ab7f0SSascha Wildner * System Call.
755*479ab7f0SSascha Wildner */
756*479ab7f0SSascha Wildnerintx30: 	cmpl $SYS_EXEC,%eax		# Exec system call?
757*479ab7f0SSascha Wildner		jne intx30.1			# No
758*479ab7f0SSascha Wildner		pushl %ss			# Set up
759*479ab7f0SSascha Wildner		popl %es			#  all
760*479ab7f0SSascha Wildner		pushl %es			#  segment
761*479ab7f0SSascha Wildner		popl %ds			#  registers
762*479ab7f0SSascha Wildner		pushl %ds			#  for the
763*479ab7f0SSascha Wildner		popl %fs			#  program
764*479ab7f0SSascha Wildner		pushl %fs			#  were
765*479ab7f0SSascha Wildner		popl %gs			#  invoking
766*479ab7f0SSascha Wildner		movl $MEM_BTX_USR,%eax		# User base address
767*479ab7f0SSascha Wildner		addl 0xc(%esp,1),%eax		# Change to user
768*479ab7f0SSascha Wildner		leal 0x4(%eax),%esp		#  stack
769*479ab7f0SSascha Wildner		popl %eax			# Call
770*479ab7f0SSascha Wildner		call *%eax			#  program
771*479ab7f0SSascha Wildnerintx30.1:	orb $0x1,%ss:btx_hdr+0x7	# Flag reboot
772*479ab7f0SSascha Wildner		jmp exit			# Exit
773*479ab7f0SSascha Wildner
774*479ab7f0SSascha Wildner/*
775*479ab7f0SSascha Wildner * Dump structure [EBX] to [EDI], using format string [ESI].
776*479ab7f0SSascha Wildner */
777*479ab7f0SSascha Wildnerdump.0: 	stosb				# Save char
778*479ab7f0SSascha Wildnerdump:		lodsb				# Load char
779*479ab7f0SSascha Wildner		testb %al,%al			# End of string?
780*479ab7f0SSascha Wildner		jz dump.10			# Yes
781*479ab7f0SSascha Wildner		testb $0x80,%al 		# Control?
782*479ab7f0SSascha Wildner		jz dump.0			# No
783*479ab7f0SSascha Wildner		movb %al,%ch			# Save control
784*479ab7f0SSascha Wildner		movb $'=',%al			# Append
785*479ab7f0SSascha Wildner		stosb				#  "="
786*479ab7f0SSascha Wildner		lodsb				# Get offset
787*479ab7f0SSascha Wildner		pushl %esi			# Save
788*479ab7f0SSascha Wildner		movsbl %al,%esi 		# To
789*479ab7f0SSascha Wildner		addl %ebx,%esi			#  pointer
790*479ab7f0SSascha Wildner		testb $DMP_X16,%ch		# Dump word?
791*479ab7f0SSascha Wildner		jz dump.1			# No
792*479ab7f0SSascha Wildner		lodsw				# Get and
793*479ab7f0SSascha Wildner		call hex16			#  dump it
794*479ab7f0SSascha Wildnerdump.1: 	testb $DMP_X32,%ch		# Dump long?
795*479ab7f0SSascha Wildner		jz dump.2			# No
796*479ab7f0SSascha Wildner		lodsl				# Get and
797*479ab7f0SSascha Wildner		call hex32			#  dump it
798*479ab7f0SSascha Wildnerdump.2: 	testb $DMP_MEM,%ch		# Dump memory?
799*479ab7f0SSascha Wildner		jz dump.8			# No
800*479ab7f0SSascha Wildner		pushl %ds			# Save
801*479ab7f0SSascha Wildner		testl $PSL_VM,0x50(%ebx)	# V86 mode?
802*479ab7f0SSascha Wildner		jnz dump.3			# Yes
803*479ab7f0SSascha Wildner		verr 0x4(%esi)	 		# Readable selector?
804*479ab7f0SSascha Wildner		jnz dump.3			# No
805*479ab7f0SSascha Wildner		ldsl (%esi),%esi		# Load pointer
806*479ab7f0SSascha Wildner		jmp dump.4			# Join common code
807*479ab7f0SSascha Wildnerdump.3: 	lodsl				# Set offset
808*479ab7f0SSascha Wildner		xchgl %eax,%edx 		# Save
809*479ab7f0SSascha Wildner		lodsl				# Get segment
810*479ab7f0SSascha Wildner		shll $0x4,%eax			#  * 0x10
811*479ab7f0SSascha Wildner		addl %edx,%eax			#  + offset
812*479ab7f0SSascha Wildner		xchgl %eax,%esi 		# Set pointer
813*479ab7f0SSascha Wildnerdump.4: 	movb $2,%dl			# Num lines
814*479ab7f0SSascha Wildnerdump.4a:	movb $0x10,%cl			# Bytes to dump
815*479ab7f0SSascha Wildnerdump.5: 	lodsb				# Get byte and
816*479ab7f0SSascha Wildner		call hex8			#  dump it
817*479ab7f0SSascha Wildner		decb %cl			# Keep count
818*479ab7f0SSascha Wildner		jz dump.6a			# If done
819*479ab7f0SSascha Wildner		movb $'-',%al			# Separator
820*479ab7f0SSascha Wildner		cmpb $0x8,%cl			# Half way?
821*479ab7f0SSascha Wildner		je dump.6			# Yes
822*479ab7f0SSascha Wildner		movb $' ',%al			# Use space
823*479ab7f0SSascha Wildnerdump.6: 	stosb				# Save separator
824*479ab7f0SSascha Wildner		jmp dump.5			# Continue
825*479ab7f0SSascha Wildnerdump.6a:	decb %dl			# Keep count
826*479ab7f0SSascha Wildner		jz dump.7			# If done
827*479ab7f0SSascha Wildner		movb $0xa,%al			# Line feed
828*479ab7f0SSascha Wildner		stosb				# Save one
829*479ab7f0SSascha Wildner		movb $7,%cl			# Leading
830*479ab7f0SSascha Wildner		movb $' ',%al			#  spaces
831*479ab7f0SSascha Wildnerdump.6b:	stosb				# Dump
832*479ab7f0SSascha Wildner		decb %cl			#  spaces
833*479ab7f0SSascha Wildner		jnz dump.6b
834*479ab7f0SSascha Wildner		jmp dump.4a			# Next line
835*479ab7f0SSascha Wildnerdump.7: 	popl %ds			# Restore
836*479ab7f0SSascha Wildnerdump.8: 	popl %esi			# Restore
837*479ab7f0SSascha Wildner		movb $0xa,%al			# Line feed
838*479ab7f0SSascha Wildner		testb $DMP_EOL,%ch		# End of line?
839*479ab7f0SSascha Wildner		jnz dump.9			# Yes
840*479ab7f0SSascha Wildner		movb $' ',%al			# Use spaces
841*479ab7f0SSascha Wildner		stosb				# Save one
842*479ab7f0SSascha Wildnerdump.9: 	jmp dump.0			# Continue
843*479ab7f0SSascha Wildnerdump.10:	stosb				# Terminate string
844*479ab7f0SSascha Wildner		ret				# To caller
845*479ab7f0SSascha Wildner
846*479ab7f0SSascha Wildner/*
847*479ab7f0SSascha Wildner * Convert EAX, AX, or AL to hex, saving the result to [EDI].
848*479ab7f0SSascha Wildner */
849*479ab7f0SSascha Wildnerhex32:		pushl %eax			# Save
850*479ab7f0SSascha Wildner		shrl $0x10,%eax 		# Do upper
851*479ab7f0SSascha Wildner		call hex16			#  16
852*479ab7f0SSascha Wildner		popl %eax			# Restore
853*479ab7f0SSascha Wildnerhex16:		call hex16.1			# Do upper 8
854*479ab7f0SSascha Wildnerhex16.1:	xchgb %ah,%al			# Save/restore
855*479ab7f0SSascha Wildnerhex8:		pushl %eax			# Save
856*479ab7f0SSascha Wildner		shrb $0x4,%al			# Do upper
857*479ab7f0SSascha Wildner		call hex8.1			#  4
858*479ab7f0SSascha Wildner		popl %eax			# Restore
859*479ab7f0SSascha Wildnerhex8.1: 	andb $0xf,%al			# Get lower 4
860*479ab7f0SSascha Wildner		cmpb $0xa,%al			# Convert
861*479ab7f0SSascha Wildner		sbbb $0x69,%al			#  to hex
862*479ab7f0SSascha Wildner		das				#  digit
863*479ab7f0SSascha Wildner		orb $0x20,%al			# To lower case
864*479ab7f0SSascha Wildner		stosb				# Save char
865*479ab7f0SSascha Wildner		ret				# (Recursive)
866*479ab7f0SSascha Wildner
867*479ab7f0SSascha Wildner/*
868*479ab7f0SSascha Wildner * Output zero-terminated string [ESI] to the console.
869*479ab7f0SSascha Wildner */
870*479ab7f0SSascha Wildnerputstr.0:	call putchr			# Output char
871*479ab7f0SSascha Wildnerputstr: 	lodsb				# Load char
872*479ab7f0SSascha Wildner		testb %al,%al			# End of string?
873*479ab7f0SSascha Wildner		jnz putstr.0			# No
874*479ab7f0SSascha Wildner		ret				# To caller
875*479ab7f0SSascha Wildner#ifdef BTX_SERIAL
876*479ab7f0SSascha Wildner		.set SIO_PRT,SIOPRT		# Base port
877*479ab7f0SSascha Wildner		.set SIO_FMT,SIOFMT		# 8N1
878*479ab7f0SSascha Wildner		.set SIO_DIV,(115200/SIOSPD)	# 115200 / SPD
879*479ab7f0SSascha Wildner
880*479ab7f0SSascha Wildner/*
881*479ab7f0SSascha Wildner * void sio_init(void)
882*479ab7f0SSascha Wildner */
883*479ab7f0SSascha Wildnersio_init:	movw $SIO_PRT+0x3,%dx		# Data format reg
884*479ab7f0SSascha Wildner		movb $SIO_FMT|0x80,%al		# Set format
885*479ab7f0SSascha Wildner		outb %al,(%dx)			#  and DLAB
886*479ab7f0SSascha Wildner		pushl %edx			# Save
887*479ab7f0SSascha Wildner		subb $0x3,%dl			# Divisor latch reg
888*479ab7f0SSascha Wildner		movw $SIO_DIV,%ax		# Set
889*479ab7f0SSascha Wildner		outw %ax,(%dx)			#  BPS
890*479ab7f0SSascha Wildner		popl %edx			# Restore
891*479ab7f0SSascha Wildner		movb $SIO_FMT,%al		# Clear
892*479ab7f0SSascha Wildner		outb %al,(%dx)			#  DLAB
893*479ab7f0SSascha Wildner		incl %edx			# Modem control reg
894*479ab7f0SSascha Wildner		movb $0x3,%al			# Set RTS,
895*479ab7f0SSascha Wildner		outb %al,(%dx)			#  DTR
896*479ab7f0SSascha Wildner		incl %edx			# Line status reg
897*479ab7f0SSascha Wildner
898*479ab7f0SSascha Wildner/*
899*479ab7f0SSascha Wildner * void sio_flush(void)
900*479ab7f0SSascha Wildner */
901*479ab7f0SSascha Wildnersio_flush.0:	call sio_getc.1 		# Get character
902*479ab7f0SSascha Wildnersio_flush:	call sio_ischar 		# Check for character
903*479ab7f0SSascha Wildner		jnz sio_flush.0 		# Till none
904*479ab7f0SSascha Wildner		ret				# To caller
905*479ab7f0SSascha Wildner
906*479ab7f0SSascha Wildner/*
907*479ab7f0SSascha Wildner * void sio_putc(int c)
908*479ab7f0SSascha Wildner */
909*479ab7f0SSascha Wildnersio_putc:	movw $SIO_PRT+0x5,%dx		# Line status reg
910*479ab7f0SSascha Wildner		xor %ecx,%ecx			# Timeout
911*479ab7f0SSascha Wildner		movb $0x40,%ch			#  counter
912*479ab7f0SSascha Wildnersio_putc.1:	inb (%dx),%al			# Transmitter
913*479ab7f0SSascha Wildner		testb $0x20,%al 		#  buffer empty?
914*479ab7f0SSascha Wildner		loopz sio_putc.1		# No
915*479ab7f0SSascha Wildner		jz sio_putc.2			# If timeout
916*479ab7f0SSascha Wildner		movb 0x4(%esp,1),%al		# Get character
917*479ab7f0SSascha Wildner		subb $0x5,%dl			# Transmitter hold reg
918*479ab7f0SSascha Wildner		outb %al,(%dx)			# Write character
919*479ab7f0SSascha Wildnersio_putc.2:	ret $0x4			# To caller
920*479ab7f0SSascha Wildner
921*479ab7f0SSascha Wildner/*
922*479ab7f0SSascha Wildner * int sio_getc(void)
923*479ab7f0SSascha Wildner */
924*479ab7f0SSascha Wildnersio_getc:	call sio_ischar 		# Character available?
925*479ab7f0SSascha Wildner		jz sio_getc			# No
926*479ab7f0SSascha Wildnersio_getc.1:	subb $0x5,%dl			# Receiver buffer reg
927*479ab7f0SSascha Wildner		inb (%dx),%al			# Read character
928*479ab7f0SSascha Wildner		ret				# To caller
929*479ab7f0SSascha Wildner
930*479ab7f0SSascha Wildner/*
931*479ab7f0SSascha Wildner * int sio_ischar(void)
932*479ab7f0SSascha Wildner */
933*479ab7f0SSascha Wildnersio_ischar:	movw $SIO_PRT+0x5,%dx		# Line status register
934*479ab7f0SSascha Wildner		xorl %eax,%eax			# Zero
935*479ab7f0SSascha Wildner		inb (%dx),%al			# Received data
936*479ab7f0SSascha Wildner		andb $0x1,%al			#  ready?
937*479ab7f0SSascha Wildner		ret				# To caller
938*479ab7f0SSascha Wildner
939*479ab7f0SSascha Wildner/*
940*479ab7f0SSascha Wildner * Output character AL to the serial console.
941*479ab7f0SSascha Wildner */
942*479ab7f0SSascha Wildnerputchr: 	pusha				# Save
943*479ab7f0SSascha Wildner		cmpb $10, %al			# is it a newline?
944*479ab7f0SSascha Wildner		jne putchr.1			#  no?, then leave
945*479ab7f0SSascha Wildner		push $13			# output a carriage
946*479ab7f0SSascha Wildner		call sio_putc			#  return first
947*479ab7f0SSascha Wildner		movb $10, %al			# restore %al
948*479ab7f0SSascha Wildnerputchr.1:	pushl %eax			# Push the character
949*479ab7f0SSascha Wildner						#  onto the stack
950*479ab7f0SSascha Wildner		call sio_putc			# Output the character
951*479ab7f0SSascha Wildner		popa				# Restore
952*479ab7f0SSascha Wildner		ret				# To caller
953*479ab7f0SSascha Wildner#else
954*479ab7f0SSascha Wildner/*
955*479ab7f0SSascha Wildner * Output character AL to the console.
956*479ab7f0SSascha Wildner */
957*479ab7f0SSascha Wildnerputchr: 	pusha				# Save
958*479ab7f0SSascha Wildner		xorl %ecx,%ecx			# Zero for loops
959*479ab7f0SSascha Wildner		movb $SCR_MAT,%ah		# Mode/attribute
960*479ab7f0SSascha Wildner		movl $BDA_POS,%ebx		# BDA pointer
961*479ab7f0SSascha Wildner		movw (%ebx),%dx 		# Cursor position
962*479ab7f0SSascha Wildner		movl $0xb8000,%edi		# Regen buffer (color)
963*479ab7f0SSascha Wildner		cmpb %ah,BDA_SCR-BDA_POS(%ebx)	# Mono mode?
964*479ab7f0SSascha Wildner		jne putchr.1			# No
965*479ab7f0SSascha Wildner		xorw %di,%di			# Regen buffer (mono)
966*479ab7f0SSascha Wildnerputchr.1:	cmpb $0xa,%al			# New line?
967*479ab7f0SSascha Wildner		je putchr.2			# Yes
968*479ab7f0SSascha Wildner		xchgl %eax,%ecx 		# Save char
969*479ab7f0SSascha Wildner		movb $SCR_COL,%al		# Columns per row
970*479ab7f0SSascha Wildner		mulb %dh			#  * row position
971*479ab7f0SSascha Wildner		addb %dl,%al			#  + column
972*479ab7f0SSascha Wildner		adcb $0x0,%ah			#  position
973*479ab7f0SSascha Wildner		shll %eax			#  * 2
974*479ab7f0SSascha Wildner		xchgl %eax,%ecx 		# Swap char, offset
975*479ab7f0SSascha Wildner		movw %ax,(%edi,%ecx,1)		# Write attr:char
976*479ab7f0SSascha Wildner		incl %edx			# Bump cursor
977*479ab7f0SSascha Wildner		cmpb $SCR_COL,%dl		# Beyond row?
978*479ab7f0SSascha Wildner		jb putchr.3			# No
979*479ab7f0SSascha Wildnerputchr.2:	xorb %dl,%dl			# Zero column
980*479ab7f0SSascha Wildner		incb %dh			# Bump row
981*479ab7f0SSascha Wildnerputchr.3:	cmpb $SCR_ROW,%dh		# Beyond screen?
982*479ab7f0SSascha Wildner		jb putchr.4			# No
983*479ab7f0SSascha Wildner		leal 2*SCR_COL(%edi),%esi	# New top line
984*479ab7f0SSascha Wildner		movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
985*479ab7f0SSascha Wildner		rep				# Scroll
986*479ab7f0SSascha Wildner		movsl				#  screen
987*479ab7f0SSascha Wildner		movb $0x20,%al			# Space
988*479ab7f0SSascha Wildner		movb $SCR_COL,%cl		# Columns to clear
989*479ab7f0SSascha Wildner		rep				# Clear
990*479ab7f0SSascha Wildner		stosw				#  line
991*479ab7f0SSascha Wildner		movb $SCR_ROW-1,%dh		# Bottom line
992*479ab7f0SSascha Wildnerputchr.4:	movw %dx,(%ebx) 		# Update position
993*479ab7f0SSascha Wildner		popa				# Restore
994*479ab7f0SSascha Wildner		ret				# To caller
995*479ab7f0SSascha Wildner#endif
996*479ab7f0SSascha Wildner
997*479ab7f0SSascha Wildner		.code16
998*479ab7f0SSascha Wildner/*
999*479ab7f0SSascha Wildner * Real Mode Hardware interrupt jump table.
1000*479ab7f0SSascha Wildner */
1001*479ab7f0SSascha Wildnerintr20: 	push $0x8			# Int 0x20: IRQ0
1002*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0x8
1003*479ab7f0SSascha Wildner		push $0x9			# Int 0x21: IRQ1
1004*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0x9
1005*479ab7f0SSascha Wildner		push $0xa			# Int 0x22: IRQ2
1006*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0xa
1007*479ab7f0SSascha Wildner		push $0xb			# Int 0x23: IRQ3
1008*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0xb
1009*479ab7f0SSascha Wildner		push $0xc			# Int 0x24: IRQ4
1010*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0xc
1011*479ab7f0SSascha Wildner		push $0xd			# Int 0x25: IRQ5
1012*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0xd
1013*479ab7f0SSascha Wildner		push $0xe			# Int 0x26: IRQ6
1014*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0xe
1015*479ab7f0SSascha Wildner		push $0xf			# Int 0x27: IRQ7
1016*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0xf
1017*479ab7f0SSascha Wildner		push $0x70			# Int 0x28: IRQ8
1018*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0x70
1019*479ab7f0SSascha Wildner		push $0x71			# Int 0x29: IRQ9
1020*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0x71
1021*479ab7f0SSascha Wildner		push $0x72			# Int 0x2a: IRQ10
1022*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0x72
1023*479ab7f0SSascha Wildner		push $0x73			# Int 0x2b: IRQ11
1024*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0x73
1025*479ab7f0SSascha Wildner		push $0x74			# Int 0x2c: IRQ12
1026*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0x74
1027*479ab7f0SSascha Wildner		push $0x75			# Int 0x2d: IRQ13
1028*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0x75
1029*479ab7f0SSascha Wildner		push $0x76			# Int 0x2e: IRQ14
1030*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0x76
1031*479ab7f0SSascha Wildner		push $0x77			# Int 0x2f: IRQ15
1032*479ab7f0SSascha Wildner		jmp int_hwr			# V86 int 0x77
1033*479ab7f0SSascha Wildner/*
1034*479ab7f0SSascha Wildner * Reflect hardware interrupts in real mode.
1035*479ab7f0SSascha Wildner */
1036*479ab7f0SSascha Wildnerint_hwr: 	push %ax			# Save
1037*479ab7f0SSascha Wildner		push %ds			# Save
1038*479ab7f0SSascha Wildner		push %bp			# Save
1039*479ab7f0SSascha Wildner		mov %sp,%bp			# Address stack frame
1040*479ab7f0SSascha Wildner		xchg %bx,6(%bp)			# Swap BX, int no
1041*479ab7f0SSascha Wildner		xor %ax,%ax			# Set %ds:%bx to
1042*479ab7f0SSascha Wildner		shl $2,%bx			#  point to
1043*479ab7f0SSascha Wildner		mov %ax,%ds			#  IDT entry
1044*479ab7f0SSascha Wildner		mov (%bx),%ax			# Load IP
1045*479ab7f0SSascha Wildner		mov 2(%bx),%bx			# Load CS
1046*479ab7f0SSascha Wildner		xchg %ax,4(%bp)			# Swap saved %ax,%bx with
1047*479ab7f0SSascha Wildner		xchg %bx,6(%bp)			#  CS:IP of handler
1048*479ab7f0SSascha Wildner		pop %bp				# Restore
1049*479ab7f0SSascha Wildner		pop %ds				# Restore
1050*479ab7f0SSascha Wildner		lret				# Jump to handler
1051*479ab7f0SSascha Wildner
1052*479ab7f0SSascha Wildner/*
1053*479ab7f0SSascha Wildner * Global descriptor table.
1054*479ab7f0SSascha Wildner *
1055*479ab7f0SSascha Wildner * 16: segment extent lsb
1056*479ab7f0SSascha Wildner * 24: segment base lsb
1057*479ab7f0SSascha Wildner *
1058*479ab7f0SSascha Wildner * 5:TYPE
1059*479ab7f0SSascha Wildner * 2:DPL
1060*479ab7f0SSascha Wildner * 1:PRESENT
1061*479ab7f0SSascha Wildner *
1062*479ab7f0SSascha Wildner * 4:  segment extent msb
1063*479ab7f0SSascha Wildner * 2:  unused
1064*479ab7f0SSascha Wildner * 1:  32 bit, else 16 bit
1065*479ab7f0SSascha Wildner * 1:  limit granularity byte/page units
1066*479ab7f0SSascha Wildner
1067*479ab7f0SSascha Wildner * 8:  segment base msb
1068*479ab7f0SSascha Wildner *
1069*479ab7f0SSascha Wildner */
1070*479ab7f0SSascha Wildner		.p2align 4
1071*479ab7f0SSascha Wildnergdt:		.word 0x0,0x0,0x0,0x0		# Null entry
1072*479ab7f0SSascha Wildner		.word 0xffff,0x0,0x9a00,0xcf	# SEL_SCODE
1073*479ab7f0SSascha Wildner		.word 0xffff,0x0,0x9200,0xcf	# SEL_SDATA
1074*479ab7f0SSascha Wildner		.word 0xffff,0x0,0x9a00,0x0	# SEL_RCODE
1075*479ab7f0SSascha Wildner		.word 0xffff,0x0,0x9200,0x0	# SEL_RDATA
1076*479ab7f0SSascha Wildner		.word 0xffff,MEM_BTX_USR,0xfa00,0xcf# SEL_UCODE
1077*479ab7f0SSascha Wildner		.word 0xffff,MEM_BTX_USR,0xf200,0xcf# SEL_UDATA
1078*479ab7f0SSascha Wildnertss_desc:	.word _TSSLM,MEM_BTX_TSS,0x8900,0x0 # SEL_TSS
1079*479ab7f0SSascha Wildnergdt.1:
1080*479ab7f0SSascha Wildner/*
1081*479ab7f0SSascha Wildner * Pseudo-descriptors.
1082*479ab7f0SSascha Wildner */
1083*479ab7f0SSascha Wildnergdtdesc:	.word gdt.1-gdt-1,gdt,0x0	# GDT
1084*479ab7f0SSascha Wildneridtdesc:	.word _IDTLM,MEM_BTX_IDT,0x0	# IDT
1085*479ab7f0SSascha Wildnerivtdesc:	.word 0x400-0x0-1,0x0,0x0	# IVT
1086*479ab7f0SSascha Wildner
1087*479ab7f0SSascha Wildner/*
1088*479ab7f0SSascha Wildner * IDT construction control string.
1089*479ab7f0SSascha Wildner */
1090*479ab7f0SSascha Wildneridtctl: 	.byte 0x10,  0x8e		# Int 0x0-0xf
1091*479ab7f0SSascha Wildner		.word 0x7dfb,intx00		#  (exceptions)
1092*479ab7f0SSascha Wildner		.byte 0x10,  0x8e		# Int 0x10
1093*479ab7f0SSascha Wildner		.word 0x1,   intx10		#  (exception)
1094*479ab7f0SSascha Wildner		.byte 0x10,  0x8e		# Int 0x20-0x2f
1095*479ab7f0SSascha Wildner		.word 0xffff,intx20		#  (hardware)
1096*479ab7f0SSascha Wildner		.byte 0x1,   0xee		# int 0x30
1097*479ab7f0SSascha Wildner		.word 0x1,   intx30		#  (system call)
1098*479ab7f0SSascha Wildner		.byte 0x2,   0xee		# Int 0x31-0x32
1099*479ab7f0SSascha Wildner		.word 0x1,   intx31		#  (V86, null)
1100*479ab7f0SSascha Wildner		.byte 0x0			# End of string
1101*479ab7f0SSascha Wildner
1102*479ab7f0SSascha Wildner/*
1103*479ab7f0SSascha Wildner * Dump format string.
1104*479ab7f0SSascha Wildner */
1105*479ab7f0SSascha Wildnerdmpfmt: 	.byte '\n'			# "\n"
1106*479ab7f0SSascha Wildner		.ascii "int"			# "int="
1107*479ab7f0SSascha Wildner		.byte 0x80|DMP_X32,	   0x40 # "00000000  "
1108*479ab7f0SSascha Wildner		.ascii "err"			# "err="
1109*479ab7f0SSascha Wildner		.byte 0x80|DMP_X32,	   0x44 # "00000000  "
1110*479ab7f0SSascha Wildner		.ascii "efl"			# "efl="
1111*479ab7f0SSascha Wildner		.byte 0x80|DMP_X32,	   0x50 # "00000000  "
1112*479ab7f0SSascha Wildner		.ascii "eip"			# "eip="
1113*479ab7f0SSascha Wildner		.byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
1114*479ab7f0SSascha Wildner		.ascii "eax"			# "eax="
1115*479ab7f0SSascha Wildner		.byte 0x80|DMP_X32,	   0x34 # "00000000  "
1116*479ab7f0SSascha Wildner		.ascii "ebx"			# "ebx="
1117*479ab7f0SSascha Wildner		.byte 0x80|DMP_X32,	   0x28 # "00000000  "
1118*479ab7f0SSascha Wildner		.ascii "ecx"			# "ecx="
1119*479ab7f0SSascha Wildner		.byte 0x80|DMP_X32,	   0x30 # "00000000  "
1120*479ab7f0SSascha Wildner		.ascii "edx"			# "edx="
1121*479ab7f0SSascha Wildner		.byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
1122*479ab7f0SSascha Wildner		.ascii "esi"			# "esi="
1123*479ab7f0SSascha Wildner		.byte 0x80|DMP_X32,	   0x1c # "00000000  "
1124*479ab7f0SSascha Wildner		.ascii "edi"			# "edi="
1125*479ab7f0SSascha Wildner		.byte 0x80|DMP_X32,	   0x18 # "00000000  "
1126*479ab7f0SSascha Wildner		.ascii "ebp"			# "ebp="
1127*479ab7f0SSascha Wildner		.byte 0x80|DMP_X32,	   0x20 # "00000000  "
1128*479ab7f0SSascha Wildner		.ascii "esp"			# "esp="
1129*479ab7f0SSascha Wildner		.byte 0x80|DMP_X32|DMP_EOL,0x0	# "00000000\n"
1130*479ab7f0SSascha Wildner		.ascii "cs"			# "cs="
1131*479ab7f0SSascha Wildner		.byte 0x80|DMP_X16,	   0x4c # "0000  "
1132*479ab7f0SSascha Wildner		.ascii "ds"			# "ds="
1133*479ab7f0SSascha Wildner		.byte 0x80|DMP_X16,	   0xc	# "0000  "
1134*479ab7f0SSascha Wildner		.ascii "es"			# "es="
1135*479ab7f0SSascha Wildner		.byte 0x80|DMP_X16,	   0x8	# "0000  "
1136*479ab7f0SSascha Wildner		.ascii "  "			# "  "
1137*479ab7f0SSascha Wildner		.ascii "fs"			# "fs="
1138*479ab7f0SSascha Wildner		.byte 0x80|DMP_X16,	   0x10 # "0000  "
1139*479ab7f0SSascha Wildner		.ascii "gs"			# "gs="
1140*479ab7f0SSascha Wildner		.byte 0x80|DMP_X16,	   0x14 # "0000  "
1141*479ab7f0SSascha Wildner		.ascii "ss"			# "ss="
1142*479ab7f0SSascha Wildner		.byte 0x80|DMP_X16|DMP_EOL,0x4	# "0000\n"
1143*479ab7f0SSascha Wildner		.ascii "cs:eip" 		# "cs:eip="
1144*479ab7f0SSascha Wildner		.byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
1145*479ab7f0SSascha Wildner		.ascii "ss:esp" 		# "ss:esp="
1146*479ab7f0SSascha Wildner		.byte 0x80|DMP_MEM|DMP_EOL,0x0	# "00 00 ... 00 00\n"
1147*479ab7f0SSascha Wildner		.asciz "BTX halted\n"		# End
1148*479ab7f0SSascha Wildner/*
1149*479ab7f0SSascha Wildner * Bad VM86 call panic
1150*479ab7f0SSascha Wildner */
1151*479ab7f0SSascha Wildnerbadvm86:	.asciz "Invalid VM86 Request\n"
1152*479ab7f0SSascha Wildner
1153*479ab7f0SSascha Wildner
1154*479ab7f0SSascha Wildner/*
1155*479ab7f0SSascha Wildner * End of BTX memory.
1156*479ab7f0SSascha Wildner */
1157*479ab7f0SSascha Wildner		.p2align 4
1158*479ab7f0SSascha Wildnerbreak:
1159