btx.S revision 86497
143561Skato#
243561Skato# Copyright (c) 1998 Robert Nordier
343561Skato# All rights reserved.
443561Skato#
543561Skato# Redistribution and use in source and binary forms are freely
643561Skato# permitted provided that the above copyright notice and this
743561Skato# paragraph and the following disclaimer are duplicated in all
843561Skato# such forms.
943561Skato#
1043561Skato# This software is provided "AS IS" and without any express or
1143561Skato# implied warranties, including, without limitation, the implied
1243561Skato# warranties of merchantability and fitness for a particular
1343561Skato# purpose.
1443561Skato#
1543561Skato
1650477Speter# $FreeBSD: head/sys/boot/pc98/btx/btx/btx.S 86497 2001-11-17 13:58:04Z nyan $
1743561Skato
1843561Skato#
1943561Skato# Memory layout.
2043561Skato#
2143561Skato		.set MEM_BTX,0x1000		# Start of BTX memory
2243561Skato		.set MEM_ESP0,0x1800		# Supervisor stack
2343561Skato		.set MEM_BUF,0x1800		# Scratch buffer
2443561Skato		.set MEM_ESP1,0x1e00		# Link stack
2543561Skato		.set MEM_IDT,0x1e00		# IDT
2643561Skato		.set MEM_TSS,0x1f98		# TSS
2743561Skato		.set MEM_MAP,0x2000		# I/O bit map
2843561Skato		.set MEM_DIR,0x4000		# Page directory
2943561Skato		.set MEM_TBL,0x5000		# Page tables
3043561Skato		.set MEM_ORG,0x9000		# BTX code
3143561Skato		.set MEM_USR,0xa000		# Start of user memory
3243561Skato#
3343561Skato# Paging control.
3443561Skato#
3543561Skato		.set PAG_SIZ,0x1000		# Page size
3643561Skato		.set PAG_CNT,0x1000		# Pages to map
3743561Skato#
3843561Skato# Segment selectors.
3943561Skato#
4043561Skato		.set SEL_SCODE,0x8		# Supervisor code
4143561Skato		.set SEL_SDATA,0x10		# Supervisor data
4243561Skato		.set SEL_RCODE,0x18		# Real mode code
4343561Skato		.set SEL_RDATA,0x20		# Real mode data
4443561Skato		.set SEL_UCODE,0x28|3		# User code
4543561Skato		.set SEL_UDATA,0x30|3		# User data
4643561Skato		.set SEL_TSS,0x38		# TSS
4743561Skato#
4843561Skato# Task state segment fields.
4943561Skato#
5043561Skato		.set TSS_ESP0,0x4		# PL 0 ESP
5143561Skato		.set TSS_SS0,0x8		# PL 0 SS
5243561Skato		.set TSS_ESP1,0xc		# PL 1 ESP
5343561Skato		.set TSS_MAP,0x66		# I/O bit map base
5443561Skato#
5543561Skato# System calls.
5643561Skato#
5743561Skato		.set SYS_EXIT,0x0		# Exit
5843561Skato		.set SYS_EXEC,0x1		# Exec
5943561Skato#
6043561Skato# V86 constants.
6143561Skato#
6243561Skato		.set V86_FLG,0x208eff		# V86 flag mask
6343561Skato		.set V86_STK,0x400		# V86 stack allowance
6443561Skato#
6543561Skato# Dump format control bytes.
6643561Skato#
6743561Skato		.set DMP_X16,0x1		# Word
6843561Skato		.set DMP_X32,0x2		# Long
6943561Skato		.set DMP_MEM,0x4		# Memory
7043561Skato		.set DMP_EOL,0x8		# End of line
7143561Skato#
7243561Skato# Screen defaults and assumptions.
7343561Skato#
7443561Skato.`ifdef' PC98
7543561Skato		.set SCR_MAT,0xe1		# Mode/attribute
7643561Skato.else
7743561Skato		.set SCR_MAT,0x7		# Mode/attribute
7843561Skato.endif
7943561Skato		.set SCR_COL,0x50		# Columns per row
8043561Skato		.set SCR_ROW,0x19		# Rows per screen
8143561Skato#
8243561Skato# BIOS Data Area locations.
8343561Skato#
8443561Skato.`ifdef' PC98
8558871Skato		.set BDA_MEM,0x501		# Free memory
8658871Skato		.set BDA_KEYFLAGS,0x53a		# Keyboard shift-state flags
8758871Skato		.set BDA_POS,0x53e		# Cursor position
8843561Skato.else
8943561Skato		.set BDA_MEM,0x413		# Free memory
9058871Skato		.set BDA_KEYFLAGS,0x417		# Keyboard shift-state flags
9143561Skato		.set BDA_SCR,0x449		# Video mode
9243561Skato		.set BDA_POS,0x450		# Cursor position
9358871Skato		.set BDA_BOOT,0x472		# Boot howto flag
9443561Skato.endif
9543561Skato#
9643561Skato# Derivations, for brevity.
9743561Skato#
9843561Skato		.set _ESP0H,MEM_ESP0>>0x8	# Byte 1 of ESP0
9943561Skato		.set _ESP1H,MEM_ESP1>>0x8	# Byte 1 of ESP1
10043561Skato		.set _TSSIO,MEM_MAP-MEM_TSS	# TSS I/O base
10143561Skato		.set _TSSLM,MEM_DIR-MEM_TSS-1	# TSS limit
10243561Skato		.set _IDTLM,MEM_TSS-MEM_IDT-1	# IDT limit
10343561Skato#
10443561Skato# Code segment.
10543561Skato#
10643561Skato		.globl start
10761064Snyan		.code16
10843561Skatostart:						# Start of code
10943561Skato#
11043561Skato# BTX header.
11143561Skato#
11243561Skatobtx_hdr:	.byte 0xeb			# Machine ID
11343561Skato		.byte 0xe			# Header size
11443561Skato		.ascii "BTX"			# Magic
11543561Skato		.byte 0x1			# Major version
11644368Skato		.byte 0x1			# Minor version
11768358Snyan		.byte BTX_FLAGS			# Flags
11843561Skato		.word PAG_CNT-MEM_ORG>>0xc	# Paging control
11943561Skato		.word break-start		# Text size
12043561Skato		.long 0x0			# Entry address
12143561Skato#
12243561Skato# Initialization routine.
12343561Skato#
12443561Skatoinit:		cli				# Disable interrupts
12561064Snyan		xor %ax,%ax			# Zero/segment
12661064Snyan		mov %ax,%ss			# Set up
12761064Snyan		mov $MEM_ESP0,%sp		#  stack
12861064Snyan		mov %ax,%es			# Address
12961064Snyan		mov %ax,%ds			#  data
13061064Snyan		pushl $0x2			# Clear
13161064Snyan		popfl				#  flags
13243561Skato#
13343561Skato# Initialize memory.
13443561Skato#
13561064Snyan		mov $MEM_IDT,%di		# Memory to initialize
13661064Snyan		mov $(MEM_ORG-MEM_IDT)/2,%cx	# Words to zero
13761064Snyan		push %di			# Save
13843561Skato		rep				# Zero-fill
13961064Snyan		stosw				#  memory
14061064Snyan		pop %di				# Restore
14143561Skato#
14243561Skato# Create IDT.
14343561Skato#
14461064Snyan		mov $idtctl,%si			# Control string
14543561Skatoinit.1: 	lodsb				# Get entry
14661064Snyan		cbw				#  count
14761064Snyan		xchg %ax,%cx			#  as word
14861064Snyan		jcxz init.4			# If done
14943561Skato		lodsb				# Get segment
15061064Snyan		xchg %ax,%dx	 		#  P:DPL:type
15161064Snyan		lodsw				# Get control
15261064Snyan		xchg %ax,%bx			#  set
15361064Snyan		lodsw				# Get handler offset
15461064Snyan		mov $SEL_SCODE,%dh		# Segment selector
15561064Snyaninit.2: 	shr %bx				# Handle this int?
15643561Skato		jnc init.3			# No
15761064Snyan		mov %ax,(%di)			# Set handler offset
15861064Snyan		mov %dh,0x2(%di)		#  and selector
15961064Snyan		mov %dl,0x5(%di)		# Set P:DPL:type
16061064Snyan		add $0x4,%ax			# Next handler
16161064Snyaninit.3: 	lea 0x8(%di),%di		# Next entry
16243561Skato		loop init.2			# Till set done
16343561Skato		jmp init.1			# Continue
16443561Skato#
16543561Skato# Initialize TSS.
16643561Skato#
16761064Snyaninit.4: 	movb $_ESP0H,TSS_ESP0+1(%di)	# Set ESP0
16861064Snyan		movb $SEL_SDATA,TSS_SS0(%di)	# Set SS0
16961064Snyan		movb $_ESP1H,TSS_ESP1+1(%di)	# Set ESP1
17061064Snyan		movb $_TSSIO,TSS_MAP(%di)	# Set I/O bit map base
17152202Skatoifdef(`PAGING',`
17243561Skato#
17343561Skato# Create page directory.
17443561Skato#
17561064Snyan		xor %edx,%edx			# Page
17661064Snyan		mov $PAG_SIZ>>0x8,%dh		#  size
17761064Snyan		xor %eax,%eax			# Zero
17861064Snyan		mov $MEM_DIR,%di		# Page directory
17961064Snyan		mov $PAG_CNT>>0xa,%cl		# Entries
18061064Snyan		mov $MEM_TBL|0x7,%ax	 	# First entry
18161064Snyaninit.5: 	stosl				# Write entry
18261064Snyan		add %dx,%ax			# To next
18343561Skato		loop init.5			# Till done
18443561Skato#
18543561Skato# Create page tables.
18643561Skato#
18761064Snyan		mov $MEM_TBL,%di		# Page table
18861064Snyan		mov $PAG_CNT>>0x8,%ch		# Entries
18961064Snyan		xor %ax,%ax			# Start address
19061064Snyaninit.6: 	mov $0x7,%al			# Set U:W:P flags
19161064Snyan		cmp btx_hdr+0x8,%cx	 	# Standard user page?
19243561Skato		jb init.7			# Yes
19361064Snyan		cmp $PAG_CNT-MEM_BTX>>0xc,%cx	# BTX memory?
19443561Skato		jae init.7			# No or first page
19561064Snyan		and $~0x2,%al			# Clear W flag
19661064Snyan		cmp $PAG_CNT-MEM_USR>>0xc,%cx	# User page zero?
19743561Skato		jne init.7			# No
19861064Snyan		testb $0x80,btx_hdr+0x7		# Unmap it?
19943561Skato		jz init.7			# No
20061064Snyan		and $~0x1,%al			# Clear P flag
20161064Snyaninit.7: 	stosl				# Set entry
20261064Snyan		add %edx,%eax			# Next address
20343561Skato		loop init.6			# Till done
20452202Skato')
20543561Skato#
20643561Skato# Bring up the system.
20743561Skato#
20861064Snyan		mov $0x2820,%bx			# Set protected mode
20961064Snyan		callw setpic			#  IRQ offsets
21061064Snyan		lidt idtdesc	 		# Set IDT
21152202Skatoifdef(`PAGING',`
21261064Snyan		xor %eax,%eax			# Set base
21361064Snyan		mov $MEM_DIR>>0x8,%ah		#  of page
21461064Snyan		mov %eax,%cr3			#  directory
21552202Skato')
21661064Snyan		lgdt gdtdesc	 		# Set GDT
21761064Snyan		mov %cr0,%eax			# Switch to protected
21852827Snyanifdef(`PAGING',`
21961064Snyan		or $0x80000001,%eax             #  mode and enable paging
22052827Snyan',`
22161064Snyan		or $0x01,%eax			#  mode
22252827Snyan')
22361064Snyan		mov %eax,%cr0			#
22461064Snyan		ljmp $SEL_SCODE,$init.8		# To 32-bit code
22561064Snyan		.code32
22643561Skatoinit.8: 	xorl %ecx,%ecx			# Zero
22743561Skato		movb $SEL_SDATA,%cl		# To 32-bit
22861064Snyan		movw %cx,%ss			#  stack
22943561Skato#
23043561Skato# Launch user task.
23143561Skato#
23243561Skato		movb $SEL_TSS,%cl		# Set task
23361064Snyan		ltr %cx				#  register
23443561Skato		movl $MEM_USR,%edx		# User base address
23543561Skato		movzwl %ss:BDA_MEM,%eax 	# Get free memory
23643561Skato.`ifdef' PC98
23743561Skato		andl $0x7,%eax
23843561Skato		incl %eax
23943561Skato		shll $0x11,%eax			# To bytes
24043561Skato.else
24143561Skato		shll $0xa,%eax			# To bytes
24243561Skato.endif
24343561Skato		subl $0x1000,%eax		# Less arg space
24443561Skato		subl %edx,%eax			# Less base
24543561Skato		movb $SEL_UDATA,%cl		# User data selector
24643561Skato		pushl %ecx			# Set SS
24743561Skato		pushl %eax			# Set ESP
24861064Snyan		push $0x202			# Set flags (IF set)
24961064Snyan		push $SEL_UCODE			# Set CS
25043561Skato		pushl btx_hdr+0xc		# Set EIP
25143561Skato		pushl %ecx			# Set GS
25243561Skato		pushl %ecx			# Set FS
25343561Skato		pushl %ecx			# Set DS
25443561Skato		pushl %ecx			# Set ES
25543561Skato		pushl %edx			# Set EAX
25643561Skato		movb $0x7,%cl			# Set remaining
25761064Snyaninit.9:		push $0x0			#  general
25843561Skato		loop init.9			#  registers
25986497Snyanifdef(`BTX_SERIAL',`
26086497Snyan		call sio_init			# setup the serial console
26186497Snyan')
26243561Skato		popa				#  and initialize
26343561Skato		popl %es			# Initialize
26443561Skato		popl %ds			#  user
26543561Skato		popl %fs			#  segment
26643561Skato		popl %gs			#  registers
26743561Skato		iret				# To user mode
26843561Skato#
26943561Skato# Exit routine.
27043561Skato#
27143561Skatoexit:		cli				# Disable interrupts
27243561Skato		movl $MEM_ESP0,%esp		# Clear stack
27343561Skato#
27443561Skato# Turn off paging.
27543561Skato#
27643561Skato		movl %cr0,%eax			# Get CR0
27743561Skato		andl $~0x80000000,%eax		# Disable
27843561Skato		movl %eax,%cr0			#  paging
27943561Skato		xorl %ecx,%ecx			# Zero
28043561Skato		movl %ecx,%cr3			# Flush TLB
28143561Skato#
28276927Snyan# Restore the GDT in case we caught a kernel trap.
28376927Snyan#
28476927Snyan		lgdt gdtdesc	 		# Set GDT
28576927Snyan#
28643561Skato# To 16 bits.
28743561Skato#
28861064Snyan		ljmpw $SEL_RCODE,$exit.1	# Reload CS
28961064Snyan		.code16
29061064Snyanexit.1: 	mov $SEL_RDATA,%cl		# 16-bit selector
29161064Snyan		mov %cx,%ss			# Reload SS
29261064Snyan		mov %cx,%ds			# Load
29361064Snyan		mov %cx,%es			#  remaining
29461064Snyan		mov %cx,%fs			#  segment
29561064Snyan		mov %cx,%gs			#  registers
29643561Skato#
29743561Skato# To real-address mode.
29843561Skato#
29961064Snyan		dec %ax				# Switch to
30061064Snyan		mov %eax,%cr0			#  real mode
30161064Snyan		ljmp $0x0,$exit.2		# Reload CS
30261064Snyanexit.2: 	xor %ax,%ax			# Real mode segment
30361064Snyan		mov %ax,%ss			# Reload SS
30461064Snyan		mov %ax,%ds			# Address data
30543561Skato.`ifdef' PC98
30661064Snyan		mov $0x1008,%bx			# Set real mode
30743561Skato.else
30861064Snyan		mov $0x7008,%bx			# Set real mode
30943561Skato.endif
31061064Snyan		callw setpic			#  IRQ offsets
31161064Snyan		lidt ivtdesc	 		# Set IVT
31243561Skato#
31343561Skato# Reboot or await reset.
31443561Skato#
31543561Skato		sti				# Enable interrupts
31661064Snyan		testb $0x1,btx_hdr+0x7		# Reboot?
31743561Skatoexit.3:		jz exit.3			# No
31843561Skato.`ifdef' PC98
31943561Skato		movb $0xa0,%al
32043561Skato		outb %al,$0x35
32143561Skato		movb 0,%al
32243561Skato		outb %al,$0xf0
32343561Skatoexit.4:		jmp exit.4
32443561Skato.else
32558871Skato		movw $0x1234, BDA_BOOT		# Do a warm boot
32661064Snyan		ljmp $0xffff,$0x0		# reboot the machine
32743561Skato.endif
32843561Skato#
32943561Skato# Set IRQ offsets by reprogramming 8259A PICs.
33043561Skato#
33143561Skato.`ifdef' PC98
33261064Snyansetpic: 	in $0x02,%al			# Save master
33361064Snyan		push %ax			#  IMR
33461064Snyan		in $0x0a,%al			# Save slave
33561064Snyan		push %ax			#  IMR
33643561Skato		movb $0x11,%al			# ICW1 to
33743561Skato		outb %al,$0x00			#  master,
33843561Skato		outb %al,$0x08			#  slave
33943561Skato		movb %bl,%al			# ICW2 to
34043561Skato		outb %al,$0x02			#  master
34143561Skato		movb %bh,%al			# ICW2 to
34243561Skato		outb %al,$0x0a			#  slave
34343561Skato		movb $0x80,%al			# ICW3 to
34443561Skato		outb %al,$0x02			#  master
34543561Skato		movb $0x7,%al			# ICW3 to
34643561Skato		outb %al,$0x0a			#  slave
34743561Skato		movb $0x1d,%al			# ICW4 to
34843561Skato		outb %al,$0x02			#  master,
34943561Skato		movb $0x9,%al			# ICW4 to
35043561Skato		outb %al,$0x0a			#  slave
35161064Snyan		pop %ax				# Restore slave
35243561Skato		outb %al,$0x0a			#  IMR
35361064Snyan		pop %ax				# Restore master
35443561Skato		outb %al,$0x02			#  IMR
35543561Skato.else
35661064Snyansetpic: 	in $0x21,%al			# Save master
35761064Snyan		push %ax			#  IMR
35861064Snyan		in $0xa1,%al			# Save slave
35961064Snyan		push %ax			#  IMR
36043561Skato		movb $0x11,%al			# ICW1 to
36143561Skato		outb %al,$0x20			#  master,
36243561Skato		outb %al,$0xa0			#  slave
36343561Skato		movb %bl,%al			# ICW2 to
36443561Skato		outb %al,$0x21			#  master
36543561Skato		movb %bh,%al			# ICW2 to
36643561Skato		outb %al,$0xa1			#  slave
36743561Skato		movb $0x4,%al			# ICW3 to
36843561Skato		outb %al,$0x21			#  master
36943561Skato		movb $0x2,%al			# ICW3 to
37043561Skato		outb %al,$0xa1			#  slave
37143561Skato		movb $0x1,%al			# ICW4 to
37243561Skato		outb %al,$0x21			#  master,
37343561Skato		outb %al,$0xa1			#  slave
37461064Snyan		pop %ax				# Restore slave
37543561Skato		outb %al,$0xa1			#  IMR
37661064Snyan		pop %ax				# Restore master
37743561Skato		outb %al,$0x21			#  IMR
37843561Skato.endif
37961064Snyan		retw				# To caller
38061064Snyan		.code32
38143561Skato#
38243561Skato# Initiate return from V86 mode to user mode.
38343561Skato#
38443561Skatointhlt: 	hlt				# To supervisor mode
38543561Skato#
38643561Skato# Exception jump table.
38743561Skato#
38861064Snyanintx00: 	push $0x0			# Int 0x0: #DE
38943561Skato		jmp ex_noc			# Divide error
39061064Snyan		push $0x1			# Int 0x1: #DB
39143561Skato		jmp ex_noc			# Debug
39261064Snyan		push $0x3			# Int 0x3: #BP
39343561Skato		jmp ex_noc			# Breakpoint
39461064Snyan		push $0x4			# Int 0x4: #OF
39543561Skato		jmp ex_noc			# Overflow
39661064Snyan		push $0x5			# Int 0x5: #BR
39743561Skato		jmp ex_noc			# BOUND range exceeded
39861064Snyan		push $0x6			# Int 0x6: #UD
39943561Skato		jmp ex_noc			# Invalid opcode
40061064Snyan		push $0x7			# Int 0x7: #NM
40143561Skato		jmp ex_noc			# Device not available
40261064Snyan		push $0x8			# Int 0x8: #DF
40343561Skato		jmp except			# Double fault
40461064Snyan		push $0xa			# Int 0xa: #TS
40543561Skato		jmp except			# Invalid TSS
40661064Snyan		push $0xb			# Int 0xb: #NP
40743561Skato		jmp except			# Segment not present
40861064Snyan		push $0xc			# Int 0xc: #SS
40943561Skato		jmp except			# Stack segment fault
41061064Snyan		push $0xd			# Int 0xd: #GP
41143561Skato		jmp ex_v86			# General protection
41261064Snyan		push $0xe			# Int 0xe: #PF
41343561Skato		jmp except			# Page fault
41461064Snyanintx10: 	push $0x10			# Int 0x10: #MF
41543561Skato		jmp ex_noc			# Floating-point error
41643561Skato#
41743561Skato# Handle #GP exception.
41843561Skato#
41943561Skatoex_v86: 	testb $0x2,0x12(%esp,1) 	# V86 mode?
42043561Skato		jz except			# No
42143561Skato		jmp v86mon			# To monitor
42243561Skato#
42343561Skato# Save a zero error code.
42443561Skato#
42543561Skatoex_noc: 	pushl (%esp,1)			# Duplicate int no
42643561Skato		movb $0x0,0x4(%esp,1)		# Fake error code
42743561Skato#
42843561Skato# Handle exception.
42943561Skato#
43043561Skatoexcept: 	cld				# String ops inc
43143561Skato		pushl %ds			# Save
43243561Skato		pushl %es			#  most
43343561Skato		pusha				#  registers
43443561Skato		movb $0x6,%al			# Push loop count
43543561Skato		testb $0x2,0x3a(%esp,1) 	# V86 mode?
43643561Skato		jnz except.1			# Yes
43743561Skato		pushl %gs			# Set GS
43843561Skato		pushl %fs			# Set FS
43943561Skato		pushl %ds			# Set DS
44043561Skato		pushl %es			# Set ES
44143561Skato		movb $0x2,%al			# Push loop count
44243561Skato		cmpw $SEL_SCODE,0x44(%esp,1)	# Supervisor mode?
44343561Skato		jne except.1			# No
44443561Skato		pushl %ss			# Set SS
44543561Skato		leal 0x50(%esp,1),%eax		# Set
44643561Skato		pushl %eax			#  ESP
44743561Skato		jmp except.2			# Join common code
44843561Skatoexcept.1:	pushl 0x50(%esp,1)		# Set GS, FS, DS, ES
44943561Skato		decb %al			#  (if V86 mode), and
45043561Skato		jne except.1			#  SS, ESP
45161064Snyanexcept.2:	push $SEL_SDATA			# Set up
45243561Skato		popl %ds			#  to
45343561Skato		pushl %ds			#  address
45443561Skato		popl %es			#  data
45543561Skato		movl %esp,%ebx			# Stack frame
45643561Skato		movl $dmpfmt,%esi		# Dump format string
45743561Skato		movl $MEM_BUF,%edi		# Buffer
45843561Skato.`ifdef' PC98
45943561Skato		pushl %eax
46043561Skato		pushl %edx
46143561Skatowait.1:
46243561Skato		inb  $0x60,%al
46343561Skato		testb $0x04,%al
46443561Skato		jz   wait.1
46543561Skato		movb $0xe0,%al
46643561Skato		outb %al,$0x62
46743561Skatowait.2:
46843561Skato		inb  $0x60,%al
46943561Skato		testb $0x01,%al
47043561Skato		jz   wait.2
47143561Skato		xorl %edx,%edx
47243561Skato		inb  $0x62,%al
47343561Skato		movb %al,%dl
47443561Skato		inb  $0x62,%al
47543561Skato		movb %al,%dh
47643561Skato		inb  $0x62,%al
47743561Skato		inb  $0x62,%al
47843561Skato		inb  $0x62,%al
47943561Skato		movl %edx,%eax
48043561Skato		shlw $1,%ax
48143561Skato		movl $BDA_POS,%edx
48243561Skato		movw %ax,(%edx)
48343561Skato		popl  %edx
48443561Skato		popl  %eax
48543561Skato.endif
48643561Skato		pushl %edi			# Dump to
48743561Skato		call dump			#  buffer
48843561Skato		popl %esi			#  and
48943561Skato		call putstr			#  display
49043561Skato		leal 0x18(%esp,1),%esp		# Discard frame
49143561Skato		popa				# Restore
49243561Skato		popl %es			#  registers
49343561Skato		popl %ds			#  saved
49443561Skato		cmpb $0x3,(%esp,1)		# Breakpoint?
49543561Skato		je except.3			# Yes
49686497Snyan		cmpb $0x1,(%esp,1)		# Debug?
49786497Snyan		jne except.2a			# No
49886497Snyan		testl $0x100,0x10(%esp,1)	# Trap flag set?
49986497Snyan		jnz except.3			# Yes
50086497Snyanexcept.2a:	jmp exit			# Exit
50143561Skatoexcept.3:	leal 0x8(%esp,1),%esp		# Discard err, int no
50243561Skato		iret				# From interrupt
50343561Skato#
50443561Skato# Return to user mode from V86 mode.
50543561Skato#
50643561Skatointrtn: 	cld				# String ops inc
50743561Skato		pushl %ds			# Address
50843561Skato		popl %es			#  data
50943561Skato		leal 0x3c(%ebp),%edx		# V86 Segment registers
51043561Skato		movl MEM_TSS+TSS_ESP1,%esi	# Link stack pointer
51143561Skato		lodsl				# INT_V86 args pointer
51243561Skato		movl %esi,%ebx			# Saved exception frame
51343561Skato		testl %eax,%eax 		# INT_V86 args?
51443561Skato		jz intrtn.2			# No
51543561Skato		movl $MEM_USR,%edi		# User base
51643561Skato		movl 0x1c(%esi),%ebx		# User ESP
51743561Skato		movl %eax,(%edi,%ebx,1) 	# Restore to user stack
51843561Skato		leal 0x8(%edi,%eax,1),%edi	# Arg segment registers
51943561Skato		testb $0x4,-0x6(%edi)		# Return flags?
52043561Skato		jz intrtn.1			# No
52143561Skato		movl 0x30(%ebp),%eax		# Get V86 flags
52243561Skato		movw %ax,0x18(%esi)		# Set user flags
52343561Skatointrtn.1:	leal 0x10(%esi),%ebx		# Saved exception frame
52443561Skato		xchgl %edx,%esi 		# Segment registers
52543561Skato		movb $0x4,%cl			# Update seg regs
52643561Skato		rep				#  in INT_V86
52743561Skato		movsl				#  args
52843561Skatointrtn.2:	movl %edx,%esi			# Segment registers
52943561Skato		leal 0x28(%ebp),%edi		# Set up seg
53043561Skato		movb $0x4,%cl			#  regs for
53143561Skato		rep				#  later
53243561Skato		movsl				#  pop
53343561Skato		movl %ebx,%esi			# Restore exception
53443561Skato		movb $0x5,%cl			#  frame to
53543561Skato		rep				#  supervisor
53643561Skato		movsl				#  stack
53743561Skato		movl %esi,MEM_TSS+TSS_ESP1	# Link stack pointer
53843561Skato		popa				# Restore
53943561Skato		leal 0x8(%esp,1),%esp		# Discard err, int no
54043561Skato		popl %es			# Restore
54143561Skato		popl %ds			#  user
54243561Skato		popl %fs			#  segment
54343561Skato		popl %gs			#  registers
54443561Skato		iret				# To user mode
54543561Skato#
54643561Skato# V86 monitor.
54743561Skato#
54843561Skatov86mon: 	cld				# String ops inc
54943561Skato		pushl $SEL_SDATA		# Set up for
55043561Skato		popl %ds			#  flat addressing
55143561Skato		pusha				# Save registers
55243561Skato		movl %esp,%ebp			# Address stack frame
55343561Skato		movzwl 0x2c(%ebp),%edi		# Load V86 CS
55443561Skato		shll $0x4,%edi			# To linear
55543561Skato		movl 0x28(%ebp),%esi		# Load V86 IP
55643561Skato		addl %edi,%esi			# Code pointer
55743561Skato		xorl %ecx,%ecx			# Zero
55843561Skato		movb $0x2,%cl			# 16-bit operands
55943561Skato		xorl %eax,%eax			# Zero
56043561Skatov86mon.1:	lodsb				# Get opcode
56143561Skato		cmpb $0x66,%al			# Operand size prefix?
56243561Skato		jne v86mon.2			# No
56343561Skato		movb $0x4,%cl			# 32-bit operands
56443561Skato		jmp v86mon.1			# Continue
56543561Skatov86mon.2:	cmpb $0xf4,%al			# HLT?
56643561Skato		jne v86mon.3			# No
56743561Skato		cmpl $inthlt+0x1,%esi		# Is inthlt?
56844368Skato		jne v86mon.7			# No (ignore)
56943561Skato		jmp intrtn			# Return to user mode
57064019Snyanv86mon.3:	cmpb $0xf,%al			# Prefixed instruction?
57164019Snyan		jne v86mon.4			# No
57264019Snyan		cmpb $0x09,(%esi)		# Is it a WBINVD?
57364019Snyan		je v86wbinvd			# Yes
57464019Snyan		cmpb $0x30,(%esi)		# Is it a WRMSR?
57564019Snyan		je v86wrmsr			# Yes
57664019Snyan		cmpb $0x32,(%esi)		# Is it a RDMSR?
57764019Snyan		je v86rdmsr			# Yes
57864019Snyan		cmpb $0x20,(%esi)		# Is this a
57944368Skato		jne v86mon.4			#  MOV EAX,CR0
58044368Skato		cmpb $0xc0,0x1(%esi)		#  instruction?
58144368Skato		je v86mov			# Yes
58244368Skatov86mon.4:	cmpb $0xfa,%al			# CLI?
58343561Skato		je v86cli			# Yes
58443561Skato		cmpb $0xfb,%al			# STI?
58543561Skato		je v86sti			# Yes
58643561Skato		movzwl 0x38(%ebp),%ebx		# Load V86 SS
58743561Skato		shll $0x4,%ebx			# To offset
58843561Skato		pushl %ebx			# Save
58943561Skato		addl 0x34(%ebp),%ebx		# Add V86 SP
59043561Skato		movl 0x30(%ebp),%edx		# Load V86 flags
59143561Skato		cmpb $0x9c,%al			# PUSHF/PUSHFD?
59243561Skato		je v86pushf			# Yes
59343561Skato		cmpb $0x9d,%al			# POPF/POPFD?
59443561Skato		je v86popf			# Yes
59543561Skato		cmpb $0xcd,%al			# INT imm8?
59643561Skato		je v86intn			# Yes
59743561Skato		cmpb $0xcf,%al			# IRET/IRETD?
59843561Skato		je v86iret			# Yes
59943561Skato		popl %ebx			# Restore
60043561Skato		popa				# Restore
60143561Skato		jmp except			# Handle exception
60244368Skatov86mon.5:	movl %edx,0x30(%ebp)		# Save V86 flags
60344368Skatov86mon.6:	popl %edx			# V86 SS adjustment
60443561Skato		subl %edx,%ebx			# Save V86
60543561Skato		movl %ebx,0x34(%ebp)		#  SP
60644368Skatov86mon.7:	subl %edi,%esi			# From linear
60743561Skato		movl %esi,0x28(%ebp)		# Save V86 IP
60843561Skato		popa				# Restore
60943561Skato		leal 0x8(%esp,1),%esp		# Discard int no, error
61043561Skato		iret				# To V86 mode
61143561Skato#
61244368Skato# Emulate MOV EAX,CR0.
61344368Skato#
61444368Skatov86mov: 	movl %cr0,%eax			# CR0 to
61544368Skato		movl %eax,0x1c(%ebp)		#  saved EAX
61664019Snyan		incl %esi			# Adjust IP
61764019Snyan#
61864019Snyan# Return from emulating a 0x0f prefixed instruction
61964019Snyan#
62064019Snyanv86preret:	incl %esi			# Adjust IP
62144368Skato		jmp v86mon.7			# Finish up
62244368Skato#
62364019Snyan# Emulate WBINVD
62464019Snyan#
62564019Snyanv86wbinvd:	wbinvd				# Write back and invalidate
62664019Snyan						#  cache
62764019Snyan		jmp v86preret			# Finish up
62864019Snyan#
62964019Snyan# Emulate WRMSR
63064019Snyan#
63164019Snyanv86wrmsr:	movl 0x18(%ebp),%ecx		# Get user's %ecx (MSR to write)
63264019Snyan		movl 0x14(%ebp),%edx		# Load the value
63364019Snyan		movl 0x1c(%ebp),%eax		#  to write
63464019Snyan		wrmsr				# Write MSR
63564019Snyan		jmp v86preret			# Finish up
63664019Snyan#
63764019Snyan# Emulate RDMSR
63864019Snyan#
63964019Snyanv86rdmsr:	movl 0x18(%ebp),%ecx		# MSR to read
64064019Snyan		rdmsr				# Read the MSR
64164019Snyan		movl %eax,0x1c(%ebp)		# Return the value of
64264019Snyan		movl %edx,0x14(%ebp)		#  the MSR to the user
64364019Snyan		jmp v86preret			# Finish up
64464019Snyan#
64543561Skato# Emulate CLI.
64643561Skato#
64743561Skatov86cli: 	andb $~0x2,0x31(%ebp)		# Clear IF
64844368Skato		jmp v86mon.7			# Finish up
64943561Skato#
65043561Skato# Emulate STI.
65143561Skato#
65243561Skatov86sti: 	orb $0x2,0x31(%ebp)		# Set IF
65344368Skato		jmp v86mon.7			# Finish up
65443561Skato#
65543561Skato# Emulate PUSHF/PUSHFD.
65643561Skato#
65743561Skatov86pushf:	subl %ecx,%ebx			# Adjust SP
65843561Skato		cmpb $0x4,%cl			# 32-bit
65943561Skato		je v86pushf.1			# Yes
66061064Snyan		data16				# 16-bit
66143561Skatov86pushf.1:	movl %edx,(%ebx)		# Save flags
66244368Skato		jmp v86mon.6			# Finish up
66343561Skato#
66443561Skato# Emulate IRET/IRETD.
66543561Skato#
66643561Skatov86iret:	movzwl (%ebx),%esi		# Load V86 IP
66743561Skato		movzwl 0x2(%ebx),%edi		# Load V86 CS
66843561Skato		leal 0x4(%ebx),%ebx		# Adjust SP
66943561Skato		movl %edi,0x2c(%ebp)		# Save V86 CS
67043561Skato		xorl %edi,%edi			# No ESI adjustment
67143561Skato#
67243561Skato# Emulate POPF/POPFD (and remainder of IRET/IRETD).
67343561Skato#
67443561Skatov86popf:	cmpb $0x4,%cl			# 32-bit?
67543561Skato		je v86popf.1			# Yes
67643561Skato		movl %edx,%eax			# Initialize
67761064Snyan		data16				# 16-bit
67843561Skatov86popf.1:	movl (%ebx),%eax		# Load flags
67943561Skato		addl %ecx,%ebx			# Adjust SP
68043561Skato		andl $V86_FLG,%eax		# Merge
68143561Skato		andl $~V86_FLG,%edx		#  the
68243561Skato		orl %eax,%edx			#  flags
68344368Skato		jmp v86mon.5			# Finish up
68443561Skato#
68552202Skato# trap int 15, function 87
68652202Skato# reads %es:%si from saved registers on stack to find a GDT containing
68752202Skato# source and destination locations
68852202Skato# reads count of words from saved %cx
68952202Skato# returns success by setting %ah to 0
69043561Skato#
69152202Skatoint15_87:	pushl %eax			# Save
69252202Skato		pushl %ebx			#  some information
69352202Skato		pushl %esi			#  onto the stack.
69452202Skato		pushl %edi
69552202Skato		xorl %eax,%eax			# clean EAX
69652202Skato		xorl %ebx,%ebx			# clean EBX
69752202Skato		movl 0x4(%ebp),%esi		# Get user's ESI
69852202Skato		movl 0x3C(%ebp),%ebx		# store ES
69952202Skato		movw %si,%ax			# store SI
70052202Skato		shll $0x4,%ebx			# Make it a seg.
70152202Skato		addl %eax,%ebx			# ebx=(es<<4)+si
70252202Skato		movb 0x14(%ebx),%al		# Grab the
70352202Skato		movb 0x17(%ebx),%ah		#  necessary
70452202Skato		shll $0x10,%eax			#  information
70552202Skato		movw 0x12(%ebx),%ax		#  from
70652202Skato		movl %eax,%esi			#  the
70752202Skato		movb 0x1c(%ebx),%al		#  GDT in order to
70852202Skato		movb 0x1f(%ebx),%ah		#  have %esi offset
70952202Skato		shll $0x10,%eax			#  of source and %edi
71052202Skato		movw 0x1a(%ebx),%ax		#  of destination.
71152202Skato		movl %eax,%edi
71252202Skato		pushl %ds			# Make:
71352202Skato		popl %es			# es = ds
71452202Skato		pushl %ecx			# stash ECX
71552202Skato		xorl %ecx,%ecx			# highw of ECX is clear
71652202Skato		movw 0x18(%ebp),%cx		# Get user's ECX
71758871Skato		shll $0x1,%ecx			# Convert from num words to num
71858871Skato						#  bytes
71952202Skato		rep				# repeat...
72052202Skato		movsb				#  perform copy.
72152202Skato		popl %ecx			# Restore
72252202Skato		popl %edi
72352202Skato		popl %esi			#  previous
72452202Skato		popl %ebx			#  register
72552202Skato		popl %eax			#  values.
72652202Skato		movb $0x0,0x1d(%ebp)		# set ah = 0 to indicate
72752202Skato						#  success
72852202Skato		andb $0xfe,%dl			# clear CF
72952202Skato		jmp v86mon.5			# Finish up
73052202Skato
73152202Skato#
73258871Skato# Reboot the machine by setting the reboot flag and exiting
73358871Skato#
73458871Skatoreboot:		orb $0x1,btx_hdr+0x7		# Set the reboot flag
73558871Skato		jmp exit			# Terminate BTX and reboot
73658871Skato
73758871Skato#
73852202Skato# Emulate INT imm8... also make sure to check if it's int 15/87
73952202Skato#
74043561Skatov86intn:	lodsb				# Get int no
74158871Skato		cmpb $0x19,%al			# is it int 19?
74258871Skato		je reboot			#  yes, reboot the machine
74352202Skato		cmpb $0x15,%al			# is it int 15?
74458871Skato		jne v86intn.3			#  no, skip parse
74552202Skato		pushl %eax                      # stash EAX
74652202Skato		movl 0x1c(%ebp),%eax		# user's saved EAX
74758871Skato		cmpb $0x87,%ah			# is it the memcpy subfunction?
74858871Skato		jne v86intn.1			#  no, keep checking
74952202Skato		popl %eax			# get the stack straight
75052202Skato		jmp int15_87			# it's our cue
75158871Skatov86intn.1:	cmpw $0x4f53,%ax		# is it the delete key callout?
75258871Skato		jne v86intn.2			#  no, handle the int normally
75358871Skato		movb BDA_KEYFLAGS,%al		# get the shift key state
75458871Skato.`ifdef' PC98
75558871Skato		andb $0x18,%al			# mask off just Ctrl and Alt
75658871Skato		cmpb $0x18,%al			# are both Ctrl and Alt down?
75758871Skato.else
75858871Skato		andb $0xc,%al			# mask off just Ctrl and Alt
75958871Skato		cmpb $0xc,%al			# are both Ctrl and Alt down?
76058871Skato.endif
76158871Skato		jne v86intn.2			#  no, handle the int normally
76258871Skato		popl %eax			# restore EAX
76358871Skato		jmp reboot			# reboot the machine
76458871Skatov86intn.2:	popl %eax			# restore EAX
76558871Skatov86intn.3:	subl %edi,%esi			# From
76643561Skato		shrl $0x4,%edi			#  linear
76743561Skato		movw %dx,-0x2(%ebx)		# Save flags
76843561Skato		movw %di,-0x4(%ebx)		# Save CS
76943561Skato		leal -0x6(%ebx),%ebx		# Adjust SP
77043561Skato		movw %si,(%ebx) 		# Save IP
77143561Skato		shll $0x2,%eax			# Scale
77243561Skato		movzwl (%eax),%esi		# Load IP
77343561Skato		movzwl 0x2(%eax),%edi		# Load CS
77443561Skato		movl %edi,0x2c(%ebp)		# Save CS
77543561Skato		xorl %edi,%edi			# No ESI adjustment
77661064Snyan		andb $~0x1,%dh			# Clear TF
77744368Skato		jmp v86mon.5			# Finish up
77843561Skato#
77943561Skato# Hardware interrupt jump table.
78043561Skato#
78161064Snyanintx20: 	push $0x8			# Int 0x20: IRQ0
78243561Skato		jmp int_hw			# V86 int 0x8
78361064Snyan		push $0x9			# Int 0x21: IRQ1
78443561Skato		jmp int_hw			# V86 int 0x9
78561064Snyan		push $0xa			# Int 0x22: IRQ2
78643561Skato		jmp int_hw			# V86 int 0xa
78761064Snyan		push $0xb			# Int 0x23: IRQ3
78843561Skato		jmp int_hw			# V86 int 0xb
78961064Snyan		push $0xc			# Int 0x24: IRQ4
79043561Skato		jmp int_hw			# V86 int 0xc
79161064Snyan		push $0xd			# Int 0x25: IRQ5
79243561Skato		jmp int_hw			# V86 int 0xd
79361064Snyan		push $0xe			# Int 0x26: IRQ6
79443561Skato		jmp int_hw			# V86 int 0xe
79561064Snyan		push $0xf			# Int 0x27: IRQ7
79643561Skato		jmp int_hw			# V86 int 0xf
79743561Skato.`ifdef' PC98
79861064Snyan		push $0x10			# Int 0x28: IRQ8
79943561Skato		jmp int_hw			# V86 int 0x10
80061064Snyan		push $0x11			# Int 0x29: IRQ9
80143561Skato		jmp int_hw			# V86 int 0x11
80261064Snyan		push $0x12			# Int 0x2a: IRQ10
80343561Skato		jmp int_hw			# V86 int 0x12
80461064Snyan		push $0x13			# Int 0x2b: IRQ11
80543561Skato		jmp int_hw			# V86 int 0x13
80661064Snyan		push $0x14			# Int 0x2c: IRQ12
80743561Skato		jmp int_hw			# V86 int 0x14
80861064Snyan		push $0x15			# Int 0x2d: IRQ13
80943561Skato		jmp int_hw			# V86 int 0x15
81061064Snyan		push $0x16			# Int 0x2e: IRQ14
81143561Skato		jmp int_hw			# V86 int 0x16
81261064Snyan		push $0x17			# Int 0x2f: IRQ15
81343561Skato		jmp int_hw			# V86 int 0x17
81443561Skato.else
81561064Snyan		push $0x70			# Int 0x28: IRQ8
81643561Skato		jmp int_hw			# V86 int 0x70
81761064Snyan		push $0x71			# Int 0x29: IRQ9
81843561Skato		jmp int_hw			# V86 int 0x71
81961064Snyan		push $0x72			# Int 0x2a: IRQ10
82043561Skato		jmp int_hw			# V86 int 0x72
82161064Snyan		push $0x73			# Int 0x2b: IRQ11
82243561Skato		jmp int_hw			# V86 int 0x73
82361064Snyan		push $0x74			# Int 0x2c: IRQ12
82443561Skato		jmp int_hw			# V86 int 0x74
82561064Snyan		push $0x75			# Int 0x2d: IRQ13
82643561Skato		jmp int_hw			# V86 int 0x75
82761064Snyan		push $0x76			# Int 0x2e: IRQ14
82843561Skato		jmp int_hw			# V86 int 0x76
82961064Snyan		push $0x77			# Int 0x2f: IRQ15
83043561Skato		jmp int_hw			# V86 int 0x77
83143561Skato.endif
83243561Skato#
83343561Skato# Reflect hardware interrupts.
83443561Skato#
83543561Skatoint_hw: 	testb $0x2,0xe(%esp,1)		# V86 mode?
83643561Skato		jz intusr			# No
83743561Skato		pushl $SEL_SDATA		# Address
83843561Skato		popl %ds			#  data
83943561Skato		xchgl %eax,(%esp,1)		# Swap EAX, int no
84043561Skato		pushl %ebp			# Address
84143561Skato		movl %esp,%ebp			#  stack frame
84243561Skato		pushl %ebx			# Save
84343561Skato		shll $0x2,%eax			# Get int
84443561Skato		movl (%eax),%eax		#  vector
84543561Skato		subl $0x6,0x14(%ebp)		# Adjust V86 ESP
84643561Skato		movzwl 0x18(%ebp),%ebx		# V86 SS
84743561Skato		shll $0x4,%ebx			#  * 0x10
84843561Skato		addl 0x14(%ebp),%ebx		#  + V86 ESP
84943561Skato		xchgw %ax,0x8(%ebp)		# Swap V86 IP
85043561Skato		rorl $0x10,%eax 		# Swap words
85143561Skato		xchgw %ax,0xc(%ebp)		# Swap V86 CS
85243561Skato		roll $0x10,%eax 		# Swap words
85343561Skato		movl %eax,(%ebx)		# CS:IP for IRET
85443561Skato		movl 0x10(%ebp),%eax		# V86 flags
85543561Skato		movw %ax,0x4(%ebx)		# Flags for IRET
85643561Skato		andb $~0x3,0x11(%ebp)		# Clear IF, TF
85743561Skato		popl %ebx			# Restore
85843561Skato		popl %ebp			#  saved
85943561Skato		popl %eax			#  registers
86043561Skato		iret				# To V86 mode
86143561Skato#
86243561Skato# Invoke V86 interrupt from user mode, with arguments.
86343561Skato#
86443561Skatointx31: 	stc				# Have btx_v86
86543561Skato		pushl %eax			# Missing int no
86643561Skato#
86743561Skato# Invoke V86 interrupt from user mode.
86843561Skato#
86943561Skatointusr: 	std				# String ops dec
87043561Skato		pushl %eax			# Expand
87143561Skato		pushl %eax			#  stack
87243561Skato		pushl %eax			#  frame
87343561Skato		pusha				# Save
87443561Skato		pushl %gs			# Save
87543561Skato		movl %esp,%eax			#  seg regs
87643561Skato		pushl %fs			#  and
87743561Skato		pushl %ds			#  point
87843561Skato		pushl %es			#  to them
87961064Snyan		push $SEL_SDATA			# Set up
88043561Skato		popl %ds			#  to
88143561Skato		pushl %ds			#  address
88243561Skato		popl %es			#  data
88343561Skato		movl $MEM_USR,%ebx		# User base
88443561Skato		movl %ebx,%edx			#  address
88543561Skato		jc intusr.1			# If btx_v86
88643561Skato		xorl %edx,%edx			# Control flags
88743561Skato		xorl %ebp,%ebp			# btx_v86 pointer
88843561Skatointusr.1:	leal 0x50(%esp,1),%esi		# Base of frame
88943561Skato		pushl %esi			# Save
89043561Skato		addl -0x4(%esi),%ebx		# User ESP
89143561Skato		movl MEM_TSS+TSS_ESP1,%edi	# Link stack pointer
89243561Skato		leal -0x4(%edi),%edi		# Adjust for push
89343561Skato		xorl %ecx,%ecx			# Zero
89443561Skato		movb $0x5,%cl			# Push exception
89543561Skato		rep				#  frame on
89643561Skato		movsl				#  link stack
89743561Skato		xchgl %eax,%esi 		# Saved seg regs
89843561Skato		movl 0x40(%esp,1),%eax		# Get int no
89943561Skato		testl %edx,%edx 		# Have btx_v86?
90043561Skato		jz intusr.2			# No
90143561Skato		movl (%ebx),%ebp		# btx_v86 pointer
90243561Skato		movb $0x4,%cl			# Count
90343561Skato		addl %ecx,%ebx			# Adjust for pop
90443561Skato		rep				# Push saved seg regs
90543561Skato		movsl				#  on link stack
90643561Skato		addl %ebp,%edx			# Flatten btx_v86 ptr
90743561Skato		leal 0x14(%edx),%esi		# Seg regs pointer
90843561Skato		movl 0x4(%edx),%eax		# Get int no/address
90943561Skato		movzwl 0x2(%edx),%edx		# Get control flags
91043561Skatointusr.2:	movl %ebp,(%edi)		# Push btx_v86 and
91143561Skato		movl %edi,MEM_TSS+TSS_ESP1	#  save link stack ptr
91243561Skato		popl %edi			# Base of frame
91343561Skato		xchgl %eax,%ebp 		# Save intno/address
91443561Skato		movl 0x48(%esp,1),%eax		# Get flags
91543561Skato		testb $0x2,%dl			# Simulate CALLF?
91643561Skato		jnz intusr.3			# Yes
91743561Skato		decl %ebx			# Push flags
91843561Skato		decl %ebx			#  on V86
91943561Skato		movw %ax,(%ebx) 		#  stack
92043561Skatointusr.3:	movb $0x4,%cl			# Count
92143561Skato		subl %ecx,%ebx			# Push return address
92243561Skato		movl $inthlt,(%ebx)		#  on V86 stack
92343561Skato		rep				# Copy seg regs to
92443561Skato		movsl				#  exception frame
92543561Skato		xchgl %eax,%ecx 		# Save flags
92643561Skato		movl %ebx,%eax			# User ESP
92743561Skato		subl $V86_STK,%eax		# Less bytes
92843561Skato		ja intusr.4			#  to
92943561Skato		xorl %eax,%eax			#  keep
93043561Skatointusr.4:	shrl $0x4,%eax			# Gives segment
93143561Skato		stosl				# Set SS
93243561Skato		shll $0x4,%eax			# To bytes
93343561Skato		xchgl %eax,%ebx 		# Swap
93443561Skato		subl %ebx,%eax			# Gives offset
93543561Skato		stosl				# Set ESP
93643561Skato		xchgl %eax,%ecx 		# Get flags
93743561Skato		btsl $0x11,%eax 		# Set VM
93861064Snyan		andb $~0x1,%ah			# Clear TF
93943561Skato		stosl				# Set EFL
94043561Skato		xchgl %eax,%ebp 		# Get int no/address
94143561Skato		testb $0x1,%dl			# Address?
94243561Skato		jnz intusr.5			# Yes
94343561Skato		shll $0x2,%eax			# Scale
94443561Skato		movl (%eax),%eax		# Load int vector
94543561Skatointusr.5:	movl %eax,%ecx			# Save
94643561Skato		shrl $0x10,%eax 		# Gives segment
94743561Skato		stosl				# Set CS
94843561Skato		movw %cx,%ax			# Restore
94943561Skato		stosl				# Set EIP
95043561Skato		leal 0x10(%esp,1),%esp		# Discard seg regs
95143561Skato		popa				# Restore
95243561Skato		iret				# To V86 mode
95343561Skato#
95443561Skato# System Call.
95543561Skato#
95643561Skatointx30: 	cmpl $SYS_EXEC,%eax		# Exec system call?
95743561Skato		jne intx30.1			# No
95843561Skato		pushl %ss			# Set up
95943561Skato		popl %es			#  all
96043561Skato		pushl %es			#  segment
96143561Skato		popl %ds			#  registers
96243561Skato		pushl %ds			#  for the
96343561Skato		popl %fs			#  program
96443561Skato		pushl %fs			#  we're
96543561Skato		popl %gs			#  invoking
96643561Skato		movl $MEM_USR,%eax		# User base address
96743561Skato		addl 0xc(%esp,1),%eax		# Change to user
96843561Skato		leal 0x4(%eax),%esp		#  stack
96956813Skatoifdef(`PAGING',`
97043561Skato		movl %cr0,%eax			# Turn
97143561Skato		andl $~0x80000000,%eax		#  off
97243561Skato		movl %eax,%cr0			#  paging
97343561Skato		xorl %eax,%eax			# Flush
97443561Skato		movl %eax,%cr3			#  TLB
97556813Skato')
97643561Skato		popl %eax			# Call
97743561Skato		call *%eax			#  program
97878650Skatointx30.1:	orb $0x1,%ss:btx_hdr+0x7	# Flag reboot
97943561Skato		jmp exit			# Exit
98043561Skato#
98143561Skato# Dump structure [EBX] to [EDI], using format string [ESI].
98243561Skato#
98343561Skatodump.0: 	stosb				# Save char
98443561Skatodump:		lodsb				# Load char
98543561Skato		testb %al,%al			# End of string?
98643561Skato		jz dump.10			# Yes
98743561Skato		testb $0x80,%al 		# Control?
98843561Skato		jz dump.0			# No
98943561Skato		movb %al,%ch			# Save control
99043561Skato		movb $'=',%al			# Append
99143561Skato		stosb				#  '='
99243561Skato		lodsb				# Get offset
99343561Skato		pushl %esi			# Save
99443561Skato		movsbl %al,%esi 		# To
99543561Skato		addl %ebx,%esi			#  pointer
99643561Skato		testb $DMP_X16,%ch		# Dump word?
99743561Skato		jz dump.1			# No
99843561Skato		lodsw				# Get and
99943561Skato		call hex16			#  dump it
100043561Skatodump.1: 	testb $DMP_X32,%ch		# Dump long?
100143561Skato		jz dump.2			# No
100243561Skato		lodsl				# Get and
100343561Skato		call hex32			#  dump it
100443561Skatodump.2: 	testb $DMP_MEM,%ch		# Dump memory?
100543561Skato		jz dump.8			# No
100643561Skato		pushl %ds			# Save
100743561Skato		testb $0x2,0x52(%ebx)		# V86 mode?
100843561Skato		jnz dump.3			# Yes
100961064Snyan		verr 0x4(%esi)	 		# Readable selector?
101043561Skato		jnz dump.3			# No
101143561Skato		ldsl (%esi),%esi		# Load pointer
101243561Skato		jmp dump.4			# Join common code
101343561Skatodump.3: 	lodsl				# Set offset
101443561Skato		xchgl %eax,%edx 		# Save
101543561Skato		lodsl				# Get segment
101643561Skato		shll $0x4,%eax			#  * 0x10
101743561Skato		addl %edx,%eax			#  + offset
101843561Skato		xchgl %eax,%esi 		# Set pointer
101986497Snyandump.4: 	movb $2,%dl			# Num lines
102086497Snyandump.4a:	movb $0x10,%cl			# Bytes to dump
102143561Skatodump.5: 	lodsb				# Get byte and
102243561Skato		call hex8			#  dump it
102343561Skato		decb %cl			# Keep count
102486497Snyan		jz dump.6a			# If done
102543561Skato		movb $'-',%al			# Separator
102643561Skato		cmpb $0x8,%cl			# Half way?
102743561Skato		je dump.6			# Yes
102843561Skato		movb $' ',%al			# Use space
102943561Skatodump.6: 	stosb				# Save separator
103043561Skato		jmp dump.5			# Continue
103186497Snyandump.6a:	decb %dl			# Keep count
103286497Snyan		jz dump.7			# If done
103386497Snyan		movb $0xa,%al			# Line feed
103486497Snyan		stosb				# Save one
103586497Snyan		movb $7,%cl			# Leading
103686497Snyan		movb $' ',%al			#  spaces
103786497Snyandump.6b:	stosb				# Dump
103886497Snyan		decb %cl			#  spaces
103986497Snyan		jnz dump.6b
104086497Snyan		jmp dump.4a			# Next line
104143561Skatodump.7: 	popl %ds			# Restore
104243561Skatodump.8: 	popl %esi			# Restore
104343561Skato		movb $0xa,%al			# Line feed
104443561Skato		testb $DMP_EOL,%ch		# End of line?
104543561Skato		jnz dump.9			# Yes
104643561Skato		movb $' ',%al			# Use spaces
104743561Skato		stosb				# Save one
104843561Skatodump.9: 	jmp dump.0			# Continue
104943561Skatodump.10:	stosb				# Terminate string
105043561Skato		ret				# To caller
105143561Skato#
105243561Skato# Convert EAX, AX, or AL to hex, saving the result to [EDI].
105343561Skato#
105443561Skatohex32:		pushl %eax			# Save
105543561Skato		shrl $0x10,%eax 		# Do upper
105643561Skato		call hex16			#  16
105743561Skato		popl %eax			# Restore
105843561Skatohex16:		call hex16.1			# Do upper 8
105943561Skatohex16.1:	xchgb %ah,%al			# Save/restore
106043561Skatohex8:		pushl %eax			# Save
106143561Skato		shrb $0x4,%al			# Do upper
106243561Skato		call hex8.1			#  4
106343561Skato		popl %eax			# Restore
106443561Skatohex8.1: 	andb $0xf,%al			# Get lower 4
106543561Skato		cmpb $0xa,%al			# Convert
106643561Skato		sbbb $0x69,%al			#  to hex
106743561Skato		das				#  digit
106843561Skato		orb $0x20,%al			# To lower case
106943561Skato		stosb				# Save char
107043561Skato		ret				# (Recursive)
107143561Skato#
107243561Skato# Output zero-terminated string [ESI] to the console.
107343561Skato#
107443561Skatoputstr.0:	call putchr			# Output char
107543561Skatoputstr: 	lodsb				# Load char
107643561Skato		testb %al,%al			# End of string?
107743561Skato		jnz putstr.0			# No
107843561Skato		ret				# To caller
107986497Snyanifdef(`BTX_SERIAL',`
108086497Snyan		.set SIO_PRT,SIOPRT		# Base port
108186497Snyan		.set SIO_FMT,SIOFMT		# 8N1
108286497Snyan		.set SIO_DIV,(115200/SIOSPD)	# 115200 / SPD
108386497Snyan
108486497Snyan# void sio_init(void)
108586497Snyan
108686497Snyansio_init:	movw $SIO_PRT+0x3,%dx		# Data format reg
108786497Snyan		movb $SIO_FMT|0x80,%al		# Set format
108886497Snyan		outb %al,(%dx)			#  and DLAB
108986497Snyan		pushl %edx			# Save
109086497Snyan		subb $0x3,%dl			# Divisor latch reg
109186497Snyan		movw $SIO_DIV,%ax		# Set
109286497Snyan		outw %ax,(%dx)			#  BPS
109386497Snyan		popl %edx			# Restore
109486497Snyan		movb $SIO_FMT,%al		# Clear
109586497Snyan		outb %al,(%dx)			#  DLAB
109686497Snyan		incl %edx			# Modem control reg
109786497Snyan		movb $0x3,%al			# Set RTS,
109886497Snyan		outb %al,(%dx)			#  DTR
109986497Snyan		incl %edx			# Line status reg
110086497Snyan
110186497Snyan# void sio_flush(void)
110286497Snyan
110386497Snyansio_flush.0:	call sio_getc.1 		# Get character
110486497Snyansio_flush:	call sio_ischar 		# Check for character
110586497Snyan		jnz sio_flush.0 		# Till none
110686497Snyan		ret				# To caller
110786497Snyan
110886497Snyan# void sio_putc(int c)
110986497Snyan
111086497Snyansio_putc:	movw $SIO_PRT+0x5,%dx		# Line status reg
111186497Snyan		xor %ecx,%ecx			# Timeout
111286497Snyan		movb $0x40,%ch			#  counter
111386497Snyansio_putc.1:	inb (%dx),%al			# Transmitter
111486497Snyan		testb $0x20,%al 		#  buffer empty?
111586497Snyan		loopz sio_putc.1		# No
111686497Snyan		jz sio_putc.2			# If timeout
111786497Snyan		movb 0x4(%esp,1),%al		# Get character
111886497Snyan		subb $0x5,%dl			# Transmitter hold reg
111986497Snyan		outb %al,(%dx)			# Write character
112086497Snyansio_putc.2:	ret $0x4			# To caller
112186497Snyan
112286497Snyan# int sio_getc(void)
112386497Snyan
112486497Snyansio_getc:	call sio_ischar 		# Character available?
112586497Snyan		jz sio_getc			# No
112686497Snyansio_getc.1:	subb $0x5,%dl			# Receiver buffer reg
112786497Snyan		inb (%dx),%al			# Read character
112886497Snyan		ret				# To caller
112986497Snyan
113086497Snyan# int sio_ischar(void)
113186497Snyan
113286497Snyansio_ischar:	movw $SIO_PRT+0x5,%dx		# Line status register
113386497Snyan		xorl %eax,%eax			# Zero
113486497Snyan		inb (%dx),%al			# Received data
113586497Snyan		andb $0x1,%al			#  ready?
113686497Snyan		ret				# To caller
113786497Snyan
113843561Skato#
113986497Snyan# Output character AL to the serial console.
114086497Snyan#
114186497Snyanputchr: 	pusha				# Save
114286497Snyan		cmpb $10, %al			# is it a newline?
114386497Snyan		jne putchr.1			#  no?, then leave
114486497Snyan		push $13			# output a carriage
114586497Snyan		call sio_putc			#  return first
114686497Snyan		movb $10, %al			# restore %al
114786497Snyanputchr.1:	pushl %eax			# Push the character
114886497Snyan						#  onto the stack
114986497Snyan		call sio_putc			# Output the character
115086497Snyan		popa				# Restore
115186497Snyan		ret				# To caller
115286497Snyan',`
115386497Snyan#
115443561Skato# Output character AL to the console.
115543561Skato#
115643561Skatoputchr: 	pusha				# Save
115743561Skato		xorl %ecx,%ecx			# Zero for loops
115843561Skato		movb $SCR_MAT,%ah		# Mode/attribute
115943561Skato		movl $BDA_POS,%ebx		# BDA pointer
116043561Skato		movw (%ebx),%dx 		# Cursor position
116143561Skato.`ifdef' PC98
116243561Skato		movl $0xa0000,%edi
116343561Skato.else
116443561Skato		movl $0xb8000,%edi		# Regen buffer (color)
116543561Skato		cmpb %ah,BDA_SCR-BDA_POS(%ebx)	# Mono mode?
116643561Skato		jne putchr.1			# No
116743561Skato		xorw %di,%di			# Regen buffer (mono)
116843561Skato.endif
116943561Skatoputchr.1:	cmpb $0xa,%al			# New line?
117043561Skato		je putchr.2			# Yes
117143561Skato.`ifdef' PC98
117243561Skato		movw %dx,%cx
117343561Skato		movb %al,(%edi,%ecx,1)		# Write char
117443561Skato		addl $0x2000,%ecx
117543561Skato		movb %ah,(%edi,%ecx,1)		# Write attr
117643561Skato		addw $0x02,%dx
117743561Skato		jmp putchr.3
117843561Skatoputchr.2:	movw %dx,%ax
117943561Skato		movb $SCR_COL*2,%dl
118043561Skato		div %dl
118143561Skato		incb %al
118243561Skato		mul %dl
118343561Skato		movw %ax,%dx
118443561Skatoputchr.3:	cmpw $SCR_ROW*SCR_COL*2,%dx
118543561Skato.else
118643561Skato		xchgl %eax,%ecx 		# Save char
118743561Skato		movb $SCR_COL,%al		# Columns per row
118843561Skato		mulb %dh			#  * row position
118943561Skato		addb %dl,%al			#  + column
119043561Skato		adcb $0x0,%ah			#  position
119143561Skato		shll %eax			#  * 2
119243561Skato		xchgl %eax,%ecx 		# Swap char, offset
119343561Skato		movw %ax,(%edi,%ecx,1)		# Write attr:char
119443561Skato		incl %edx			# Bump cursor
119543561Skato		cmpb $SCR_COL,%dl		# Beyond row?
119643561Skato		jb putchr.3			# No
119743561Skatoputchr.2:	xorb %dl,%dl			# Zero column
119843561Skato		incb %dh			# Bump row
119943561Skatoputchr.3:	cmpb $SCR_ROW,%dh		# Beyond screen?
120043561Skato.endif
120143561Skato		jb putchr.4			# No
120243561Skato		leal 2*SCR_COL(%edi),%esi	# New top line
120343561Skato		movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
120443561Skato		rep				# Scroll
120543561Skato		movsl				#  screen
120686497Snyan		movb $0x20,%al			# Space
120743561Skato.`ifdef' PC98
120843561Skato		xorb %ah,%ah
120943561Skato.endif
121043561Skato		movb $SCR_COL,%cl		# Columns to clear
121143561Skato		rep				# Clear
121243561Skato		stosw				#  line
121343561Skato.`ifdef' PC98
121443561Skato		movw $(SCR_ROW-1)*SCR_COL*2,%dx
121543561Skato.else
121643561Skato		movb $SCR_ROW-1,%dh		# Bottom line
121743561Skato.endif
121843561Skatoputchr.4:	movw %dx,(%ebx) 		# Update position
121943561Skato		popa				# Restore
122043561Skato		ret				# To caller
122186497Snyan')
122243561Skato
122343561Skato		.p2align 4
122443561Skato#
122543561Skato# Global descriptor table.
122643561Skato#
122743561Skatogdt:		.word 0x0,0x0,0x0,0x0		# Null entry
122843561Skato		.word 0xffff,0x0,0x9a00,0xcf	# SEL_SCODE
122943561Skato		.word 0xffff,0x0,0x9200,0xcf	# SEL_SDATA
123043561Skato		.word 0xffff,0x0,0x9a00,0x0	# SEL_RCODE
123143561Skato		.word 0xffff,0x0,0x9200,0x0	# SEL_RDATA
123243561Skato		.word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
123343561Skato		.word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
123443561Skato		.word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
123543561Skatogdt.1:
123643561Skato#
123743561Skato# Pseudo-descriptors.
123843561Skato#
123943561Skatogdtdesc:	.word gdt.1-gdt-1,gdt,0x0	# GDT
124043561Skatoidtdesc:	.word _IDTLM,MEM_IDT,0x0	# IDT
124143561Skatoivtdesc:	.word 0x400-0x0-1,0x0,0x0	# IVT
124243561Skato#
124343561Skato# IDT construction control string.
124443561Skato#
124543561Skatoidtctl: 	.byte 0x10,  0x8e		# Int 0x0-0xf
124643561Skato		.word 0x7dfb,intx00		#  (exceptions)
124743561Skato		.byte 0x10,  0x8e		# Int 0x10
124843561Skato		.word 0x1,   intx10		#  (exception)
124943561Skato		.byte 0x10,  0x8e		# Int 0x20-0x2f
125043561Skato		.word 0xffff,intx20		#  (hardware)
125143561Skato		.byte 0x1,   0xee		# int 0x30
125243561Skato		.word 0x1,   intx30		#  (system call)
125343561Skato		.byte 0x2,   0xee		# Int 0x31-0x32
125443561Skato		.word 0x1,   intx31		#  (V86, null)
125543561Skato		.byte 0x0			# End of string
125643561Skato#
125743561Skato# Dump format string.
125843561Skato#
125943561Skatodmpfmt: 	.byte '\n'			# "\n"
126043561Skato		.ascii "int"			# "int="
126143561Skato		.byte 0x80|DMP_X32,	   0x40 # "00000000  "
126243561Skato		.ascii "err"			# "err="
126343561Skato		.byte 0x80|DMP_X32,	   0x44 # "00000000  "
126443561Skato		.ascii "efl"			# "efl="
126543561Skato		.byte 0x80|DMP_X32,	   0x50 # "00000000  "
126643561Skato		.ascii "eip"			# "eip="
126743561Skato		.byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
126843561Skato		.ascii "eax"			# "eax="
126943561Skato		.byte 0x80|DMP_X32,	   0x34 # "00000000  "
127043561Skato		.ascii "ebx"			# "ebx="
127143561Skato		.byte 0x80|DMP_X32,	   0x28 # "00000000  "
127243561Skato		.ascii "ecx"			# "ecx="
127343561Skato		.byte 0x80|DMP_X32,	   0x30 # "00000000  "
127443561Skato		.ascii "edx"			# "edx="
127543561Skato		.byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
127643561Skato		.ascii "esi"			# "esi="
127743561Skato		.byte 0x80|DMP_X32,	   0x1c # "00000000  "
127843561Skato		.ascii "edi"			# "edi="
127943561Skato		.byte 0x80|DMP_X32,	   0x18 # "00000000  "
128043561Skato		.ascii "ebp"			# "ebp="
128143561Skato		.byte 0x80|DMP_X32,	   0x20 # "00000000  "
128243561Skato		.ascii "esp"			# "esp="
128343561Skato		.byte 0x80|DMP_X32|DMP_EOL,0x0	# "00000000\n"
128443561Skato		.ascii "cs"			# "cs="
128543561Skato		.byte 0x80|DMP_X16,	   0x4c # "0000  "
128643561Skato		.ascii "ds"			# "ds="
128743561Skato		.byte 0x80|DMP_X16,	   0xc	# "0000  "
128843561Skato		.ascii "es"			# "es="
128943561Skato		.byte 0x80|DMP_X16,	   0x8	# "0000  "
129043561Skato		.ascii "  "			# "  "
129143561Skato		.ascii "fs"			# "fs="
129243561Skato		.byte 0x80|DMP_X16,	   0x10 # "0000  "
129343561Skato		.ascii "gs"			# "gs="
129443561Skato		.byte 0x80|DMP_X16,	   0x14 # "0000  "
129543561Skato		.ascii "ss"			# "ss="
129643561Skato		.byte 0x80|DMP_X16|DMP_EOL,0x4	# "0000\n"
129743561Skato		.ascii "cs:eip" 		# "cs:eip="
129843561Skato		.byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
129943561Skato		.ascii "ss:esp" 		# "ss:esp="
130043561Skato		.byte 0x80|DMP_MEM|DMP_EOL,0x0	# "00 00 ... 00 00\n"
130186497Snyan		.asciz "BTX halted\n"		# End
130243561Skato#
130343561Skato# End of BTX memory.
130443561Skato#
130543561Skato		.p2align 4
130643561Skatobreak:
1307