btx.S revision 164114
1128710Sru/*
2128710Sru * Copyright (c) 1998 Robert Nordier
3128710Sru * All rights reserved.
4128710Sru *
5128710Sru * Redistribution and use in source and binary forms are freely
6128710Sru * permitted provided that the above copyright notice and this
7128710Sru * paragraph and the following disclaimer are duplicated in all
8128710Sru * such forms.
9128710Sru *
10128710Sru * This software is provided "AS IS" and without any express or
11128710Sru * implied warranties, including, without limitation, the implied
12128710Sru * warranties of merchantability and fitness for a particular
13128710Sru * purpose.
14128710Sru *
15128710Sru * $FreeBSD: head/sys/boot/pc98/btx/btx/btx.S 164114 2006-11-09 08:05:51Z nyan $
16128710Sru */
1743561Skato
18128710Sru/*
19128710Sru * Memory layout.
20128710Sru */
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
32128710Sru/*
33128710Sru * Paging control.
34128710Sru */
3543561Skato		.set PAG_SIZ,0x1000		# Page size
3643561Skato		.set PAG_CNT,0x1000		# Pages to map
37128710Sru/*
38128710Sru * Segment selectors.
39128710Sru */
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
47128710Sru/*
48128710Sru * Task state segment fields.
49128710Sru */
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
54128710Sru/*
55128710Sru * System calls.
56128710Sru */
5743561Skato		.set SYS_EXIT,0x0		# Exit
5843561Skato		.set SYS_EXEC,0x1		# Exec
59128710Sru/*
60128710Sru * V86 constants.
61128710Sru */
6243561Skato		.set V86_FLG,0x208eff		# V86 flag mask
6343561Skato		.set V86_STK,0x400		# V86 stack allowance
64128710Sru/*
65128710Sru * Dump format control bytes.
66128710Sru */
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
71128710Sru/*
72128710Sru * Screen defaults and assumptions.
73128710Sru */
7443561Skato		.set SCR_MAT,0xe1		# Mode/attribute
7543561Skato		.set SCR_COL,0x50		# Columns per row
7643561Skato		.set SCR_ROW,0x19		# Rows per screen
77128710Sru/*
78128710Sru * BIOS Data Area locations.
79128710Sru */
8058871Skato		.set BDA_MEM,0x501		# Free memory
8158871Skato		.set BDA_KEYFLAGS,0x53a		# Keyboard shift-state flags
8258871Skato		.set BDA_POS,0x53e		# Cursor position
83128710Sru/*
84128710Sru * Derivations, for brevity.
85128710Sru */
8643561Skato		.set _ESP0H,MEM_ESP0>>0x8	# Byte 1 of ESP0
8743561Skato		.set _ESP1H,MEM_ESP1>>0x8	# Byte 1 of ESP1
8843561Skato		.set _TSSIO,MEM_MAP-MEM_TSS	# TSS I/O base
8943561Skato		.set _TSSLM,MEM_DIR-MEM_TSS-1	# TSS limit
9043561Skato		.set _IDTLM,MEM_TSS-MEM_IDT-1	# IDT limit
91128710Sru/*
92128710Sru * Code segment.
93128710Sru */
9443561Skato		.globl start
9561064Snyan		.code16
9643561Skatostart:						# Start of code
97128710Sru/*
98128710Sru * BTX header.
99128710Sru */
10043561Skatobtx_hdr:	.byte 0xeb			# Machine ID
10143561Skato		.byte 0xe			# Header size
10243561Skato		.ascii "BTX"			# Magic
10343561Skato		.byte 0x1			# Major version
10444368Skato		.byte 0x1			# Minor version
10568358Snyan		.byte BTX_FLAGS			# Flags
10643561Skato		.word PAG_CNT-MEM_ORG>>0xc	# Paging control
10743561Skato		.word break-start		# Text size
10843561Skato		.long 0x0			# Entry address
109128710Sru/*
110128710Sru * Initialization routine.
111128710Sru */
11243561Skatoinit:		cli				# Disable interrupts
11361064Snyan		xor %ax,%ax			# Zero/segment
11461064Snyan		mov %ax,%ss			# Set up
11561064Snyan		mov $MEM_ESP0,%sp		#  stack
11661064Snyan		mov %ax,%es			# Address
11761064Snyan		mov %ax,%ds			#  data
11861064Snyan		pushl $0x2			# Clear
11961064Snyan		popfl				#  flags
120128710Sru/*
121128710Sru * Initialize memory.
122128710Sru */
12361064Snyan		mov $MEM_IDT,%di		# Memory to initialize
12461064Snyan		mov $(MEM_ORG-MEM_IDT)/2,%cx	# Words to zero
12561064Snyan		push %di			# Save
12643561Skato		rep				# Zero-fill
12761064Snyan		stosw				#  memory
12861064Snyan		pop %di				# Restore
129128710Sru/*
130128710Sru * Create IDT.
131128710Sru */
13261064Snyan		mov $idtctl,%si			# Control string
13343561Skatoinit.1: 	lodsb				# Get entry
13461064Snyan		cbw				#  count
13561064Snyan		xchg %ax,%cx			#  as word
13661064Snyan		jcxz init.4			# If done
13743561Skato		lodsb				# Get segment
13861064Snyan		xchg %ax,%dx	 		#  P:DPL:type
13961064Snyan		lodsw				# Get control
14061064Snyan		xchg %ax,%bx			#  set
14161064Snyan		lodsw				# Get handler offset
14261064Snyan		mov $SEL_SCODE,%dh		# Segment selector
14361064Snyaninit.2: 	shr %bx				# Handle this int?
14443561Skato		jnc init.3			# No
14561064Snyan		mov %ax,(%di)			# Set handler offset
14661064Snyan		mov %dh,0x2(%di)		#  and selector
14761064Snyan		mov %dl,0x5(%di)		# Set P:DPL:type
14861064Snyan		add $0x4,%ax			# Next handler
14961064Snyaninit.3: 	lea 0x8(%di),%di		# Next entry
15043561Skato		loop init.2			# Till set done
15143561Skato		jmp init.1			# Continue
152128710Sru/*
153128710Sru * Initialize TSS.
154128710Sru */
15561064Snyaninit.4: 	movb $_ESP0H,TSS_ESP0+1(%di)	# Set ESP0
15661064Snyan		movb $SEL_SDATA,TSS_SS0(%di)	# Set SS0
15761064Snyan		movb $_ESP1H,TSS_ESP1+1(%di)	# Set ESP1
15861064Snyan		movb $_TSSIO,TSS_MAP(%di)	# Set I/O bit map base
159125780Snyan#ifdef PAGING
160128710Sru/*
161128710Sru * Create page directory.
162128710Sru */
16361064Snyan		xor %edx,%edx			# Page
16461064Snyan		mov $PAG_SIZ>>0x8,%dh		#  size
16561064Snyan		xor %eax,%eax			# Zero
16661064Snyan		mov $MEM_DIR,%di		# Page directory
16761064Snyan		mov $PAG_CNT>>0xa,%cl		# Entries
16861064Snyan		mov $MEM_TBL|0x7,%ax	 	# First entry
16961064Snyaninit.5: 	stosl				# Write entry
17061064Snyan		add %dx,%ax			# To next
17143561Skato		loop init.5			# Till done
172128710Sru/*
173128710Sru * Create page tables.
174128710Sru */
17561064Snyan		mov $MEM_TBL,%di		# Page table
17661064Snyan		mov $PAG_CNT>>0x8,%ch		# Entries
17761064Snyan		xor %ax,%ax			# Start address
17861064Snyaninit.6: 	mov $0x7,%al			# Set U:W:P flags
17961064Snyan		cmp btx_hdr+0x8,%cx	 	# Standard user page?
18043561Skato		jb init.7			# Yes
18161064Snyan		cmp $PAG_CNT-MEM_BTX>>0xc,%cx	# BTX memory?
18243561Skato		jae init.7			# No or first page
18361064Snyan		and $~0x2,%al			# Clear W flag
18461064Snyan		cmp $PAG_CNT-MEM_USR>>0xc,%cx	# User page zero?
18543561Skato		jne init.7			# No
18661064Snyan		testb $0x80,btx_hdr+0x7		# Unmap it?
18743561Skato		jz init.7			# No
18861064Snyan		and $~0x1,%al			# Clear P flag
18961064Snyaninit.7: 	stosl				# Set entry
19061064Snyan		add %edx,%eax			# Next address
19143561Skato		loop init.6			# Till done
192125780Snyan#endif
193128710Sru/*
194128710Sru * Bring up the system.
195128710Sru */
19661064Snyan		mov $0x2820,%bx			# Set protected mode
19761064Snyan		callw setpic			#  IRQ offsets
19861064Snyan		lidt idtdesc	 		# Set IDT
199125780Snyan#ifdef PAGING
20061064Snyan		xor %eax,%eax			# Set base
20161064Snyan		mov $MEM_DIR>>0x8,%ah		#  of page
20261064Snyan		mov %eax,%cr3			#  directory
203125780Snyan#endif
20461064Snyan		lgdt gdtdesc	 		# Set GDT
20561064Snyan		mov %cr0,%eax			# Switch to protected
206125780Snyan#ifdef PAGING
20761064Snyan		or $0x80000001,%eax             #  mode and enable paging
208125780Snyan#else
209164114Snyan		inc %ax				#  mode
210125780Snyan#endif
211128710Sru		mov %eax,%cr0			#
21261064Snyan		ljmp $SEL_SCODE,$init.8		# To 32-bit code
21361064Snyan		.code32
21443561Skatoinit.8: 	xorl %ecx,%ecx			# Zero
21543561Skato		movb $SEL_SDATA,%cl		# To 32-bit
21661064Snyan		movw %cx,%ss			#  stack
217128710Sru/*
218128710Sru * Launch user task.
219128710Sru */
22043561Skato		movb $SEL_TSS,%cl		# Set task
22161064Snyan		ltr %cx				#  register
22243561Skato		movl $MEM_USR,%edx		# User base address
22343561Skato		movzwl %ss:BDA_MEM,%eax 	# Get free memory
22443561Skato		andl $0x7,%eax
22543561Skato		incl %eax
22643561Skato		shll $0x11,%eax			# To bytes
22743561Skato		subl $0x1000,%eax		# Less arg space
22843561Skato		subl %edx,%eax			# Less base
22943561Skato		movb $SEL_UDATA,%cl		# User data selector
23043561Skato		pushl %ecx			# Set SS
23143561Skato		pushl %eax			# Set ESP
23261064Snyan		push $0x202			# Set flags (IF set)
23361064Snyan		push $SEL_UCODE			# Set CS
23443561Skato		pushl btx_hdr+0xc		# Set EIP
23543561Skato		pushl %ecx			# Set GS
23643561Skato		pushl %ecx			# Set FS
23743561Skato		pushl %ecx			# Set DS
23843561Skato		pushl %ecx			# Set ES
23943561Skato		pushl %edx			# Set EAX
24043561Skato		movb $0x7,%cl			# Set remaining
24161064Snyaninit.9:		push $0x0			#  general
24243561Skato		loop init.9			#  registers
243125780Snyan#ifdef BTX_SERIAL
24486497Snyan		call sio_init			# setup the serial console
245125780Snyan#endif
24643561Skato		popa				#  and initialize
24743561Skato		popl %es			# Initialize
24843561Skato		popl %ds			#  user
24943561Skato		popl %fs			#  segment
25043561Skato		popl %gs			#  registers
25143561Skato		iret				# To user mode
252128710Sru/*
253128710Sru * Exit routine.
254128710Sru */
25543561Skatoexit:		cli				# Disable interrupts
25643561Skato		movl $MEM_ESP0,%esp		# Clear stack
257128710Sru/*
258128710Sru * Turn off paging.
259128710Sru */
26043561Skato		movl %cr0,%eax			# Get CR0
26143561Skato		andl $~0x80000000,%eax		# Disable
26243561Skato		movl %eax,%cr0			#  paging
26343561Skato		xorl %ecx,%ecx			# Zero
26443561Skato		movl %ecx,%cr3			# Flush TLB
265128710Sru/*
266128710Sru * Restore the GDT in case we caught a kernel trap.
267128710Sru */
26876927Snyan		lgdt gdtdesc	 		# Set GDT
269128710Sru/*
270128710Sru * To 16 bits.
271128710Sru */
27261064Snyan		ljmpw $SEL_RCODE,$exit.1	# Reload CS
27361064Snyan		.code16
27461064Snyanexit.1: 	mov $SEL_RDATA,%cl		# 16-bit selector
27561064Snyan		mov %cx,%ss			# Reload SS
27661064Snyan		mov %cx,%ds			# Load
27761064Snyan		mov %cx,%es			#  remaining
27861064Snyan		mov %cx,%fs			#  segment
27961064Snyan		mov %cx,%gs			#  registers
280128710Sru/*
281128710Sru * To real-address mode.
282128710Sru */
28361064Snyan		dec %ax				# Switch to
28461064Snyan		mov %eax,%cr0			#  real mode
28561064Snyan		ljmp $0x0,$exit.2		# Reload CS
28661064Snyanexit.2: 	xor %ax,%ax			# Real mode segment
28761064Snyan		mov %ax,%ss			# Reload SS
28861064Snyan		mov %ax,%ds			# Address data
28961064Snyan		mov $0x1008,%bx			# Set real mode
29061064Snyan		callw setpic			#  IRQ offsets
29161064Snyan		lidt ivtdesc	 		# Set IVT
292128710Sru/*
293128710Sru * Reboot or await reset.
294128710Sru */
29543561Skato		sti				# Enable interrupts
29661064Snyan		testb $0x1,btx_hdr+0x7		# Reboot?
29743561Skatoexit.3:		jz exit.3			# No
29843561Skato		movb $0xa0,%al
29943561Skato		outb %al,$0x35
30043561Skato		movb 0,%al
30143561Skato		outb %al,$0xf0
30243561Skatoexit.4:		jmp exit.4
303128710Sru/*
304128710Sru * Set IRQ offsets by reprogramming 8259A PICs.
305128710Sru */
30661064Snyansetpic: 	in $0x02,%al			# Save master
30761064Snyan		push %ax			#  IMR
30861064Snyan		in $0x0a,%al			# Save slave
30961064Snyan		push %ax			#  IMR
31043561Skato		movb $0x11,%al			# ICW1 to
31143561Skato		outb %al,$0x00			#  master,
31243561Skato		outb %al,$0x08			#  slave
31343561Skato		movb %bl,%al			# ICW2 to
31443561Skato		outb %al,$0x02			#  master
31543561Skato		movb %bh,%al			# ICW2 to
31643561Skato		outb %al,$0x0a			#  slave
31743561Skato		movb $0x80,%al			# ICW3 to
31843561Skato		outb %al,$0x02			#  master
31943561Skato		movb $0x7,%al			# ICW3 to
32043561Skato		outb %al,$0x0a			#  slave
32143561Skato		movb $0x1d,%al			# ICW4 to
32243561Skato		outb %al,$0x02			#  master,
32343561Skato		movb $0x9,%al			# ICW4 to
32443561Skato		outb %al,$0x0a			#  slave
32561064Snyan		pop %ax				# Restore slave
32643561Skato		outb %al,$0x0a			#  IMR
32761064Snyan		pop %ax				# Restore master
32843561Skato		outb %al,$0x02			#  IMR
32961064Snyan		retw				# To caller
33061064Snyan		.code32
331128710Sru/*
332128710Sru * Initiate return from V86 mode to user mode.
333128710Sru */
33443561Skatointhlt: 	hlt				# To supervisor mode
335128710Sru/*
336128710Sru * Exception jump table.
337128710Sru */
33861064Snyanintx00: 	push $0x0			# Int 0x0: #DE
33943561Skato		jmp ex_noc			# Divide error
34061064Snyan		push $0x1			# Int 0x1: #DB
34143561Skato		jmp ex_noc			# Debug
34261064Snyan		push $0x3			# Int 0x3: #BP
34343561Skato		jmp ex_noc			# Breakpoint
34461064Snyan		push $0x4			# Int 0x4: #OF
34543561Skato		jmp ex_noc			# Overflow
34661064Snyan		push $0x5			# Int 0x5: #BR
34743561Skato		jmp ex_noc			# BOUND range exceeded
34861064Snyan		push $0x6			# Int 0x6: #UD
34943561Skato		jmp ex_noc			# Invalid opcode
35061064Snyan		push $0x7			# Int 0x7: #NM
35143561Skato		jmp ex_noc			# Device not available
35261064Snyan		push $0x8			# Int 0x8: #DF
35343561Skato		jmp except			# Double fault
35461064Snyan		push $0xa			# Int 0xa: #TS
35543561Skato		jmp except			# Invalid TSS
35661064Snyan		push $0xb			# Int 0xb: #NP
35743561Skato		jmp except			# Segment not present
35861064Snyan		push $0xc			# Int 0xc: #SS
35943561Skato		jmp except			# Stack segment fault
36061064Snyan		push $0xd			# Int 0xd: #GP
36143561Skato		jmp ex_v86			# General protection
36261064Snyan		push $0xe			# Int 0xe: #PF
36343561Skato		jmp except			# Page fault
36461064Snyanintx10: 	push $0x10			# Int 0x10: #MF
36543561Skato		jmp ex_noc			# Floating-point error
366128710Sru/*
367128710Sru * Handle #GP exception.
368128710Sru */
36943561Skatoex_v86: 	testb $0x2,0x12(%esp,1) 	# V86 mode?
37043561Skato		jz except			# No
37143561Skato		jmp v86mon			# To monitor
372128710Sru/*
373128710Sru * Save a zero error code.
374128710Sru */
37543561Skatoex_noc: 	pushl (%esp,1)			# Duplicate int no
37643561Skato		movb $0x0,0x4(%esp,1)		# Fake error code
377128710Sru/*
378128710Sru * Handle exception.
379128710Sru */
38043561Skatoexcept: 	cld				# String ops inc
38143561Skato		pushl %ds			# Save
38243561Skato		pushl %es			#  most
38343561Skato		pusha				#  registers
38443561Skato		movb $0x6,%al			# Push loop count
38543561Skato		testb $0x2,0x3a(%esp,1) 	# V86 mode?
38643561Skato		jnz except.1			# Yes
38743561Skato		pushl %gs			# Set GS
38843561Skato		pushl %fs			# Set FS
38943561Skato		pushl %ds			# Set DS
39043561Skato		pushl %es			# Set ES
39143561Skato		movb $0x2,%al			# Push loop count
39243561Skato		cmpw $SEL_SCODE,0x44(%esp,1)	# Supervisor mode?
39343561Skato		jne except.1			# No
39443561Skato		pushl %ss			# Set SS
39543561Skato		leal 0x50(%esp,1),%eax		# Set
39643561Skato		pushl %eax			#  ESP
39743561Skato		jmp except.2			# Join common code
39843561Skatoexcept.1:	pushl 0x50(%esp,1)		# Set GS, FS, DS, ES
39943561Skato		decb %al			#  (if V86 mode), and
40043561Skato		jne except.1			#  SS, ESP
40161064Snyanexcept.2:	push $SEL_SDATA			# Set up
40243561Skato		popl %ds			#  to
40343561Skato		pushl %ds			#  address
40443561Skato		popl %es			#  data
40543561Skato		movl %esp,%ebx			# Stack frame
40643561Skato		movl $dmpfmt,%esi		# Dump format string
40743561Skato		movl $MEM_BUF,%edi		# Buffer
40843561Skato		pushl %eax
40943561Skato		pushl %edx
41043561Skatowait.1:
41143561Skato		inb  $0x60,%al
41243561Skato		testb $0x04,%al
41343561Skato		jz   wait.1
41443561Skato		movb $0xe0,%al
41543561Skato		outb %al,$0x62
41643561Skatowait.2:
41743561Skato		inb  $0x60,%al
41843561Skato		testb $0x01,%al
41943561Skato		jz   wait.2
42043561Skato		xorl %edx,%edx
42143561Skato		inb  $0x62,%al
42243561Skato		movb %al,%dl
42343561Skato		inb  $0x62,%al
42443561Skato		movb %al,%dh
42543561Skato		inb  $0x62,%al
42643561Skato		inb  $0x62,%al
42743561Skato		inb  $0x62,%al
42843561Skato		movl %edx,%eax
42943561Skato		shlw $1,%ax
43043561Skato		movl $BDA_POS,%edx
43143561Skato		movw %ax,(%edx)
43243561Skato		popl  %edx
43343561Skato		popl  %eax
43443561Skato		pushl %edi			# Dump to
43543561Skato		call dump			#  buffer
43643561Skato		popl %esi			#  and
43743561Skato		call putstr			#  display
43843561Skato		leal 0x18(%esp,1),%esp		# Discard frame
43943561Skato		popa				# Restore
44043561Skato		popl %es			#  registers
44143561Skato		popl %ds			#  saved
44243561Skato		cmpb $0x3,(%esp,1)		# Breakpoint?
44343561Skato		je except.3			# Yes
44486497Snyan		cmpb $0x1,(%esp,1)		# Debug?
44586497Snyan		jne except.2a			# No
44686497Snyan		testl $0x100,0x10(%esp,1)	# Trap flag set?
44786497Snyan		jnz except.3			# Yes
44886497Snyanexcept.2a:	jmp exit			# Exit
44943561Skatoexcept.3:	leal 0x8(%esp,1),%esp		# Discard err, int no
45043561Skato		iret				# From interrupt
451128710Sru/*
452128710Sru * Return to user mode from V86 mode.
453128710Sru */
45443561Skatointrtn: 	cld				# String ops inc
45543561Skato		pushl %ds			# Address
45643561Skato		popl %es			#  data
45743561Skato		leal 0x3c(%ebp),%edx		# V86 Segment registers
45843561Skato		movl MEM_TSS+TSS_ESP1,%esi	# Link stack pointer
45943561Skato		lodsl				# INT_V86 args pointer
46043561Skato		movl %esi,%ebx			# Saved exception frame
46143561Skato		testl %eax,%eax 		# INT_V86 args?
46243561Skato		jz intrtn.2			# No
46343561Skato		movl $MEM_USR,%edi		# User base
46443561Skato		movl 0x1c(%esi),%ebx		# User ESP
46543561Skato		movl %eax,(%edi,%ebx,1) 	# Restore to user stack
46643561Skato		leal 0x8(%edi,%eax,1),%edi	# Arg segment registers
46743561Skato		testb $0x4,-0x6(%edi)		# Return flags?
46843561Skato		jz intrtn.1			# No
46943561Skato		movl 0x30(%ebp),%eax		# Get V86 flags
47043561Skato		movw %ax,0x18(%esi)		# Set user flags
47143561Skatointrtn.1:	leal 0x10(%esi),%ebx		# Saved exception frame
47243561Skato		xchgl %edx,%esi 		# Segment registers
47343561Skato		movb $0x4,%cl			# Update seg regs
47443561Skato		rep				#  in INT_V86
47543561Skato		movsl				#  args
476164114Snyanintrtn.2:	xchgl %edx,%esi			# Segment registers
47743561Skato		leal 0x28(%ebp),%edi		# Set up seg
47843561Skato		movb $0x4,%cl			#  regs for
47943561Skato		rep				#  later
48043561Skato		movsl				#  pop
481164114Snyan		xchgl %ebx,%esi			# Restore exception
48243561Skato		movb $0x5,%cl			#  frame to
48343561Skato		rep				#  supervisor
48443561Skato		movsl				#  stack
48543561Skato		movl %esi,MEM_TSS+TSS_ESP1	# Link stack pointer
48643561Skato		popa				# Restore
48743561Skato		leal 0x8(%esp,1),%esp		# Discard err, int no
48843561Skato		popl %es			# Restore
48943561Skato		popl %ds			#  user
49043561Skato		popl %fs			#  segment
49143561Skato		popl %gs			#  registers
49243561Skato		iret				# To user mode
493128710Sru/*
494128710Sru * V86 monitor.
495128710Sru */
49643561Skatov86mon: 	cld				# String ops inc
49743561Skato		pushl $SEL_SDATA		# Set up for
49843561Skato		popl %ds			#  flat addressing
49943561Skato		pusha				# Save registers
50043561Skato		movl %esp,%ebp			# Address stack frame
50143561Skato		movzwl 0x2c(%ebp),%edi		# Load V86 CS
50243561Skato		shll $0x4,%edi			# To linear
50343561Skato		movl 0x28(%ebp),%esi		# Load V86 IP
50443561Skato		addl %edi,%esi			# Code pointer
50543561Skato		xorl %ecx,%ecx			# Zero
50643561Skato		movb $0x2,%cl			# 16-bit operands
50743561Skato		xorl %eax,%eax			# Zero
50843561Skatov86mon.1:	lodsb				# Get opcode
50943561Skato		cmpb $0x66,%al			# Operand size prefix?
51043561Skato		jne v86mon.2			# No
51143561Skato		movb $0x4,%cl			# 32-bit operands
51243561Skato		jmp v86mon.1			# Continue
51343561Skatov86mon.2:	cmpb $0xf4,%al			# HLT?
51443561Skato		jne v86mon.3			# No
51543561Skato		cmpl $inthlt+0x1,%esi		# Is inthlt?
51644368Skato		jne v86mon.7			# No (ignore)
51743561Skato		jmp intrtn			# Return to user mode
51864019Snyanv86mon.3:	cmpb $0xf,%al			# Prefixed instruction?
51964019Snyan		jne v86mon.4			# No
52064019Snyan		cmpb $0x09,(%esi)		# Is it a WBINVD?
52164019Snyan		je v86wbinvd			# Yes
52264019Snyan		cmpb $0x30,(%esi)		# Is it a WRMSR?
52364019Snyan		je v86wrmsr			# Yes
52464019Snyan		cmpb $0x32,(%esi)		# Is it a RDMSR?
52564019Snyan		je v86rdmsr			# Yes
526164114Snyan		cmpb $0x20,(%esi)		# Is this a MOV reg,CRx?
52744368Skato		je v86mov			# Yes
52844368Skatov86mon.4:	cmpb $0xfa,%al			# CLI?
52943561Skato		je v86cli			# Yes
53043561Skato		cmpb $0xfb,%al			# STI?
53143561Skato		je v86sti			# Yes
53243561Skato		movzwl 0x38(%ebp),%ebx		# Load V86 SS
53343561Skato		shll $0x4,%ebx			# To offset
53443561Skato		pushl %ebx			# Save
53543561Skato		addl 0x34(%ebp),%ebx		# Add V86 SP
53643561Skato		movl 0x30(%ebp),%edx		# Load V86 flags
53743561Skato		cmpb $0x9c,%al			# PUSHF/PUSHFD?
53843561Skato		je v86pushf			# Yes
53943561Skato		cmpb $0x9d,%al			# POPF/POPFD?
54043561Skato		je v86popf			# Yes
54143561Skato		cmpb $0xcd,%al			# INT imm8?
54243561Skato		je v86intn			# Yes
54343561Skato		cmpb $0xcf,%al			# IRET/IRETD?
54443561Skato		je v86iret			# Yes
54543561Skato		popl %ebx			# Restore
54643561Skato		popa				# Restore
54743561Skato		jmp except			# Handle exception
54844368Skatov86mon.5:	movl %edx,0x30(%ebp)		# Save V86 flags
54944368Skatov86mon.6:	popl %edx			# V86 SS adjustment
55043561Skato		subl %edx,%ebx			# Save V86
55143561Skato		movl %ebx,0x34(%ebp)		#  SP
55244368Skatov86mon.7:	subl %edi,%esi			# From linear
55343561Skato		movl %esi,0x28(%ebp)		# Save V86 IP
55443561Skato		popa				# Restore
55543561Skato		leal 0x8(%esp,1),%esp		# Discard int no, error
55643561Skato		iret				# To V86 mode
557128710Sru/*
558164114Snyan * Emulate MOV reg,CRx.
559128710Sru */
560164114Snyanv86mov: 	movb 0x1(%esi),%bl		# Fetch Mod R/M byte
561164114Snyan		testb $0x10,%bl			# Read CR2 or CR3?
562164114Snyan		jnz v86mov.1			# Yes
563164114Snyan		movl %cr0,%eax			# Read CR0
564164114Snyan		testb $0x20,%bl			# Read CR4 instead?
565164114Snyan		jz v86mov.2			# No
566164114Snyan		movl %cr4,%eax			# Read CR4
567164114Snyan		jmp v86mov.2
568164114Snyanv86mov.1:	movl %cr2,%eax			# Read CR2
569164114Snyan		testb $0x08,%bl			# Read CR3 instead?
570164114Snyan		jz v86mov.2			# No
571164114Snyan		movl %cr3,%eax			# Read CR3
572164114Snyanv86mov.2:	andl $0x7,%ebx			# Compute offset in
573164114Snyan		shl $2,%ebx			#  frame of destination
574164114Snyan		neg %ebx			#  register
575164114Snyan		movl %eax,0x1c(%ebp,%ebx,1)	# Store CR to reg
57664019Snyan		incl %esi			# Adjust IP
577128710Sru/*
578128710Sru * Return from emulating a 0x0f prefixed instruction
579128710Sru */
58064019Snyanv86preret:	incl %esi			# Adjust IP
58144368Skato		jmp v86mon.7			# Finish up
582128710Sru/*
583128710Sru * Emulate WBINVD
584128710Sru */
58564019Snyanv86wbinvd:	wbinvd				# Write back and invalidate
58664019Snyan						#  cache
58764019Snyan		jmp v86preret			# Finish up
588128710Sru/*
589128710Sru * Emulate WRMSR
590128710Sru */
59164019Snyanv86wrmsr:	movl 0x18(%ebp),%ecx		# Get user's %ecx (MSR to write)
59264019Snyan		movl 0x14(%ebp),%edx		# Load the value
59364019Snyan		movl 0x1c(%ebp),%eax		#  to write
59464019Snyan		wrmsr				# Write MSR
59564019Snyan		jmp v86preret			# Finish up
596128710Sru/*
597128710Sru * Emulate RDMSR
598128710Sru */
59964019Snyanv86rdmsr:	movl 0x18(%ebp),%ecx		# MSR to read
60064019Snyan		rdmsr				# Read the MSR
60164019Snyan		movl %eax,0x1c(%ebp)		# Return the value of
60264019Snyan		movl %edx,0x14(%ebp)		#  the MSR to the user
60364019Snyan		jmp v86preret			# Finish up
604128710Sru/*
605128710Sru * Emulate CLI.
606128710Sru */
60743561Skatov86cli: 	andb $~0x2,0x31(%ebp)		# Clear IF
60844368Skato		jmp v86mon.7			# Finish up
609128710Sru/*
610128710Sru * Emulate STI.
611128710Sru */
61243561Skatov86sti: 	orb $0x2,0x31(%ebp)		# Set IF
61344368Skato		jmp v86mon.7			# Finish up
614128710Sru/*
615128710Sru * Emulate PUSHF/PUSHFD.
616128710Sru */
61743561Skatov86pushf:	subl %ecx,%ebx			# Adjust SP
61843561Skato		cmpb $0x4,%cl			# 32-bit
61943561Skato		je v86pushf.1			# Yes
62061064Snyan		data16				# 16-bit
62143561Skatov86pushf.1:	movl %edx,(%ebx)		# Save flags
62244368Skato		jmp v86mon.6			# Finish up
623128710Sru/*
624128710Sru * Emulate IRET/IRETD.
625128710Sru */
62643561Skatov86iret:	movzwl (%ebx),%esi		# Load V86 IP
62743561Skato		movzwl 0x2(%ebx),%edi		# Load V86 CS
62843561Skato		leal 0x4(%ebx),%ebx		# Adjust SP
62943561Skato		movl %edi,0x2c(%ebp)		# Save V86 CS
63043561Skato		xorl %edi,%edi			# No ESI adjustment
631128710Sru/*
632128710Sru * Emulate POPF/POPFD (and remainder of IRET/IRETD).
633128710Sru */
63443561Skatov86popf:	cmpb $0x4,%cl			# 32-bit?
63543561Skato		je v86popf.1			# Yes
63643561Skato		movl %edx,%eax			# Initialize
63761064Snyan		data16				# 16-bit
63843561Skatov86popf.1:	movl (%ebx),%eax		# Load flags
63943561Skato		addl %ecx,%ebx			# Adjust SP
64043561Skato		andl $V86_FLG,%eax		# Merge
64143561Skato		andl $~V86_FLG,%edx		#  the
64243561Skato		orl %eax,%edx			#  flags
64344368Skato		jmp v86mon.5			# Finish up
644128710Sru/*
645128710Sru * trap int 15, function 87
646128710Sru * reads %es:%si from saved registers on stack to find a GDT containing
647128710Sru * source and destination locations
648128710Sru * reads count of words from saved %cx
649128710Sru * returns success by setting %ah to 0
650128710Sru */
651164114Snyanint15_87:	pushl %esi			# Save
652164114Snyan		pushl %edi			#  registers
653164114Snyan		movl 0x3C(%ebp),%edi		# Load ES
654164114Snyan		movzwl 0x4(%ebp),%eax		# Load user's SI
655164114Snyan		shll $0x4,%edi			# EDI = (ES << 4) +
656164114Snyan		addl %eax,%edi			#   SI
657164114Snyan		movl 0x11(%edi),%eax		# Read base of
658164114Snyan		movb 0x17(%edi),%al		#  GDT entry
659164114Snyan		ror $8,%eax			#  for source
660164114Snyan		xchgl %eax,%esi			#  into %esi
661164114Snyan		movl 0x19(%edi),%eax		# Read base of
662164114Snyan		movb 0x1f(%edi),%al		#  GDT entry for
663164114Snyan		ror $8,%eax			#  destination
664164114Snyan		xchgl %eax,%edi			#  into %edi
66552202Skato		pushl %ds			# Make:
66652202Skato		popl %es			# es = ds
667164114Snyan		movzwl 0x18(%ebp),%ecx		# Get user's CX
668164114Snyan		shll $0x1,%ecx			# Convert count from words
66952202Skato		rep				# repeat...
67052202Skato		movsb				#  perform copy.
671164114Snyan		popl %edi			# Restore
672164114Snyan		popl %esi			#  registers
67352202Skato		movb $0x0,0x1d(%ebp)		# set ah = 0 to indicate
67452202Skato						#  success
67552202Skato		andb $0xfe,%dl			# clear CF
67652202Skato		jmp v86mon.5			# Finish up
67752202Skato
678128710Sru/*
679128710Sru * Reboot the machine by setting the reboot flag and exiting
680128710Sru */
68158871Skatoreboot:		orb $0x1,btx_hdr+0x7		# Set the reboot flag
68258871Skato		jmp exit			# Terminate BTX and reboot
68358871Skato
684128710Sru/*
685128710Sru * Emulate INT imm8... also make sure to check if it's int 15/87
686128710Sru */
68743561Skatov86intn:	lodsb				# Get int no
68858871Skato		cmpb $0x19,%al			# is it int 19?
68958871Skato		je reboot			#  yes, reboot the machine
69052202Skato		cmpb $0x15,%al			# is it int 15?
691164114Snyan		jne v86intn.1			#  no, skip parse
692164114Snyan		cmpb $0x87,0x1d(%ebp)		# is it the memcpy subfunction?
693164114Snyan		je int15_87			#  yes
694164114Snyan		cmpw $0x4f53,0x1c(%ebp)		# is it the delete key callout?
695164114Snyan		jne v86intn.1			#  no, handle the int normally
696164114Snyan		movb BDA_KEYFLAGS,%ch		# get the shift key state
697164114Snyan		andb $0x18,%ch			# mask off just Ctrl and Alt
698164114Snyan		cmpb $0x18,%ch			# are both Ctrl and Alt down?
699164114Snyan		je reboot			# yes, reboot the machine
700164114Snyanv86intn.1:	subl %edi,%esi			# From
70143561Skato		shrl $0x4,%edi			#  linear
70243561Skato		movw %dx,-0x2(%ebx)		# Save flags
70343561Skato		movw %di,-0x4(%ebx)		# Save CS
70443561Skato		leal -0x6(%ebx),%ebx		# Adjust SP
70543561Skato		movw %si,(%ebx) 		# Save IP
70643561Skato		shll $0x2,%eax			# Scale
70743561Skato		movzwl (%eax),%esi		# Load IP
70843561Skato		movzwl 0x2(%eax),%edi		# Load CS
70943561Skato		movl %edi,0x2c(%ebp)		# Save CS
71043561Skato		xorl %edi,%edi			# No ESI adjustment
71161064Snyan		andb $~0x1,%dh			# Clear TF
71244368Skato		jmp v86mon.5			# Finish up
713128710Sru/*
714128710Sru * Hardware interrupt jump table.
715128710Sru */
71661064Snyanintx20: 	push $0x8			# Int 0x20: IRQ0
71743561Skato		jmp int_hw			# V86 int 0x8
71861064Snyan		push $0x9			# Int 0x21: IRQ1
71943561Skato		jmp int_hw			# V86 int 0x9
72061064Snyan		push $0xa			# Int 0x22: IRQ2
72143561Skato		jmp int_hw			# V86 int 0xa
72261064Snyan		push $0xb			# Int 0x23: IRQ3
72343561Skato		jmp int_hw			# V86 int 0xb
72461064Snyan		push $0xc			# Int 0x24: IRQ4
72543561Skato		jmp int_hw			# V86 int 0xc
72661064Snyan		push $0xd			# Int 0x25: IRQ5
72743561Skato		jmp int_hw			# V86 int 0xd
72861064Snyan		push $0xe			# Int 0x26: IRQ6
72943561Skato		jmp int_hw			# V86 int 0xe
73061064Snyan		push $0xf			# Int 0x27: IRQ7
73143561Skato		jmp int_hw			# V86 int 0xf
73261064Snyan		push $0x10			# Int 0x28: IRQ8
73343561Skato		jmp int_hw			# V86 int 0x10
73461064Snyan		push $0x11			# Int 0x29: IRQ9
73543561Skato		jmp int_hw			# V86 int 0x11
73661064Snyan		push $0x12			# Int 0x2a: IRQ10
73743561Skato		jmp int_hw			# V86 int 0x12
73861064Snyan		push $0x13			# Int 0x2b: IRQ11
73943561Skato		jmp int_hw			# V86 int 0x13
74061064Snyan		push $0x14			# Int 0x2c: IRQ12
74143561Skato		jmp int_hw			# V86 int 0x14
74261064Snyan		push $0x15			# Int 0x2d: IRQ13
74343561Skato		jmp int_hw			# V86 int 0x15
74461064Snyan		push $0x16			# Int 0x2e: IRQ14
74543561Skato		jmp int_hw			# V86 int 0x16
74661064Snyan		push $0x17			# Int 0x2f: IRQ15
74743561Skato		jmp int_hw			# V86 int 0x17
748128710Sru/*
749128710Sru * Reflect hardware interrupts.
750128710Sru */
75143561Skatoint_hw: 	testb $0x2,0xe(%esp,1)		# V86 mode?
75243561Skato		jz intusr			# No
75343561Skato		pushl $SEL_SDATA		# Address
75443561Skato		popl %ds			#  data
75543561Skato		xchgl %eax,(%esp,1)		# Swap EAX, int no
75643561Skato		pushl %ebp			# Address
75743561Skato		movl %esp,%ebp			#  stack frame
75843561Skato		pushl %ebx			# Save
75943561Skato		shll $0x2,%eax			# Get int
76043561Skato		movl (%eax),%eax		#  vector
76143561Skato		subl $0x6,0x14(%ebp)		# Adjust V86 ESP
76243561Skato		movzwl 0x18(%ebp),%ebx		# V86 SS
76343561Skato		shll $0x4,%ebx			#  * 0x10
76443561Skato		addl 0x14(%ebp),%ebx		#  + V86 ESP
76543561Skato		xchgw %ax,0x8(%ebp)		# Swap V86 IP
76643561Skato		rorl $0x10,%eax 		# Swap words
76743561Skato		xchgw %ax,0xc(%ebp)		# Swap V86 CS
76843561Skato		roll $0x10,%eax 		# Swap words
76943561Skato		movl %eax,(%ebx)		# CS:IP for IRET
77043561Skato		movl 0x10(%ebp),%eax		# V86 flags
77143561Skato		movw %ax,0x4(%ebx)		# Flags for IRET
77243561Skato		andb $~0x3,0x11(%ebp)		# Clear IF, TF
77343561Skato		popl %ebx			# Restore
77443561Skato		popl %ebp			#  saved
77543561Skato		popl %eax			#  registers
77643561Skato		iret				# To V86 mode
777128710Sru/*
778128710Sru * Invoke V86 interrupt from user mode, with arguments.
779128710Sru */
78043561Skatointx31: 	stc				# Have btx_v86
78143561Skato		pushl %eax			# Missing int no
782128710Sru/*
783128710Sru * Invoke V86 interrupt from user mode.
784128710Sru */
78543561Skatointusr: 	std				# String ops dec
78643561Skato		pushl %eax			# Expand
78743561Skato		pushl %eax			#  stack
78843561Skato		pushl %eax			#  frame
78943561Skato		pusha				# Save
79043561Skato		pushl %gs			# Save
79143561Skato		movl %esp,%eax			#  seg regs
79243561Skato		pushl %fs			#  and
79343561Skato		pushl %ds			#  point
79443561Skato		pushl %es			#  to them
79561064Snyan		push $SEL_SDATA			# Set up
79643561Skato		popl %ds			#  to
79743561Skato		pushl %ds			#  address
79843561Skato		popl %es			#  data
79943561Skato		movl $MEM_USR,%ebx		# User base
80043561Skato		movl %ebx,%edx			#  address
80143561Skato		jc intusr.1			# If btx_v86
80243561Skato		xorl %edx,%edx			# Control flags
80343561Skato		xorl %ebp,%ebp			# btx_v86 pointer
80443561Skatointusr.1:	leal 0x50(%esp,1),%esi		# Base of frame
80543561Skato		pushl %esi			# Save
80643561Skato		addl -0x4(%esi),%ebx		# User ESP
80743561Skato		movl MEM_TSS+TSS_ESP1,%edi	# Link stack pointer
80843561Skato		leal -0x4(%edi),%edi		# Adjust for push
80943561Skato		xorl %ecx,%ecx			# Zero
81043561Skato		movb $0x5,%cl			# Push exception
81143561Skato		rep				#  frame on
81243561Skato		movsl				#  link stack
81343561Skato		xchgl %eax,%esi 		# Saved seg regs
81443561Skato		movl 0x40(%esp,1),%eax		# Get int no
81543561Skato		testl %edx,%edx 		# Have btx_v86?
81643561Skato		jz intusr.2			# No
81743561Skato		movl (%ebx),%ebp		# btx_v86 pointer
81843561Skato		movb $0x4,%cl			# Count
81943561Skato		addl %ecx,%ebx			# Adjust for pop
82043561Skato		rep				# Push saved seg regs
82143561Skato		movsl				#  on link stack
82243561Skato		addl %ebp,%edx			# Flatten btx_v86 ptr
82343561Skato		leal 0x14(%edx),%esi		# Seg regs pointer
82443561Skato		movl 0x4(%edx),%eax		# Get int no/address
82543561Skato		movzwl 0x2(%edx),%edx		# Get control flags
82643561Skatointusr.2:	movl %ebp,(%edi)		# Push btx_v86 and
82743561Skato		movl %edi,MEM_TSS+TSS_ESP1	#  save link stack ptr
82843561Skato		popl %edi			# Base of frame
82943561Skato		xchgl %eax,%ebp 		# Save intno/address
83043561Skato		movl 0x48(%esp,1),%eax		# Get flags
83143561Skato		testb $0x2,%dl			# Simulate CALLF?
83243561Skato		jnz intusr.3			# Yes
83343561Skato		decl %ebx			# Push flags
83443561Skato		decl %ebx			#  on V86
83543561Skato		movw %ax,(%ebx) 		#  stack
83643561Skatointusr.3:	movb $0x4,%cl			# Count
83743561Skato		subl %ecx,%ebx			# Push return address
83843561Skato		movl $inthlt,(%ebx)		#  on V86 stack
83943561Skato		rep				# Copy seg regs to
84043561Skato		movsl				#  exception frame
84143561Skato		xchgl %eax,%ecx 		# Save flags
84243561Skato		movl %ebx,%eax			# User ESP
84343561Skato		subl $V86_STK,%eax		# Less bytes
84443561Skato		ja intusr.4			#  to
84543561Skato		xorl %eax,%eax			#  keep
84643561Skatointusr.4:	shrl $0x4,%eax			# Gives segment
84743561Skato		stosl				# Set SS
84843561Skato		shll $0x4,%eax			# To bytes
84943561Skato		xchgl %eax,%ebx 		# Swap
85043561Skato		subl %ebx,%eax			# Gives offset
85143561Skato		stosl				# Set ESP
85243561Skato		xchgl %eax,%ecx 		# Get flags
85343561Skato		btsl $0x11,%eax 		# Set VM
85461064Snyan		andb $~0x1,%ah			# Clear TF
85543561Skato		stosl				# Set EFL
85643561Skato		xchgl %eax,%ebp 		# Get int no/address
85743561Skato		testb $0x1,%dl			# Address?
85843561Skato		jnz intusr.5			# Yes
85943561Skato		shll $0x2,%eax			# Scale
86043561Skato		movl (%eax),%eax		# Load int vector
86143561Skatointusr.5:	movl %eax,%ecx			# Save
86243561Skato		shrl $0x10,%eax 		# Gives segment
86343561Skato		stosl				# Set CS
86443561Skato		movw %cx,%ax			# Restore
86543561Skato		stosl				# Set EIP
86643561Skato		leal 0x10(%esp,1),%esp		# Discard seg regs
86743561Skato		popa				# Restore
86843561Skato		iret				# To V86 mode
869128710Sru/*
870128710Sru * System Call.
871128710Sru */
87243561Skatointx30: 	cmpl $SYS_EXEC,%eax		# Exec system call?
87343561Skato		jne intx30.1			# No
87443561Skato		pushl %ss			# Set up
87543561Skato		popl %es			#  all
87643561Skato		pushl %es			#  segment
87743561Skato		popl %ds			#  registers
87843561Skato		pushl %ds			#  for the
87943561Skato		popl %fs			#  program
88043561Skato		pushl %fs			#  we're
88143561Skato		popl %gs			#  invoking
88243561Skato		movl $MEM_USR,%eax		# User base address
88343561Skato		addl 0xc(%esp,1),%eax		# Change to user
88443561Skato		leal 0x4(%eax),%esp		#  stack
885125780Snyan#ifdef PAGING
88643561Skato		movl %cr0,%eax			# Turn
88743561Skato		andl $~0x80000000,%eax		#  off
88843561Skato		movl %eax,%cr0			#  paging
88943561Skato		xorl %eax,%eax			# Flush
89043561Skato		movl %eax,%cr3			#  TLB
891125780Snyan#endif
89243561Skato		popl %eax			# Call
89343561Skato		call *%eax			#  program
89478650Skatointx30.1:	orb $0x1,%ss:btx_hdr+0x7	# Flag reboot
89543561Skato		jmp exit			# Exit
896128710Sru/*
897128710Sru * Dump structure [EBX] to [EDI], using format string [ESI].
898128710Sru */
89943561Skatodump.0: 	stosb				# Save char
90043561Skatodump:		lodsb				# Load char
90143561Skato		testb %al,%al			# End of string?
90243561Skato		jz dump.10			# Yes
90343561Skato		testb $0x80,%al 		# Control?
90443561Skato		jz dump.0			# No
90543561Skato		movb %al,%ch			# Save control
90643561Skato		movb $'=',%al			# Append
90743561Skato		stosb				#  '='
90843561Skato		lodsb				# Get offset
90943561Skato		pushl %esi			# Save
91043561Skato		movsbl %al,%esi 		# To
91143561Skato		addl %ebx,%esi			#  pointer
91243561Skato		testb $DMP_X16,%ch		# Dump word?
91343561Skato		jz dump.1			# No
91443561Skato		lodsw				# Get and
91543561Skato		call hex16			#  dump it
91643561Skatodump.1: 	testb $DMP_X32,%ch		# Dump long?
91743561Skato		jz dump.2			# No
91843561Skato		lodsl				# Get and
91943561Skato		call hex32			#  dump it
92043561Skatodump.2: 	testb $DMP_MEM,%ch		# Dump memory?
92143561Skato		jz dump.8			# No
92243561Skato		pushl %ds			# Save
92343561Skato		testb $0x2,0x52(%ebx)		# V86 mode?
92443561Skato		jnz dump.3			# Yes
92561064Snyan		verr 0x4(%esi)	 		# Readable selector?
92643561Skato		jnz dump.3			# No
92743561Skato		ldsl (%esi),%esi		# Load pointer
92843561Skato		jmp dump.4			# Join common code
92943561Skatodump.3: 	lodsl				# Set offset
93043561Skato		xchgl %eax,%edx 		# Save
93143561Skato		lodsl				# Get segment
93243561Skato		shll $0x4,%eax			#  * 0x10
93343561Skato		addl %edx,%eax			#  + offset
93443561Skato		xchgl %eax,%esi 		# Set pointer
93586497Snyandump.4: 	movb $2,%dl			# Num lines
93686497Snyandump.4a:	movb $0x10,%cl			# Bytes to dump
93743561Skatodump.5: 	lodsb				# Get byte and
93843561Skato		call hex8			#  dump it
93943561Skato		decb %cl			# Keep count
94086497Snyan		jz dump.6a			# If done
94143561Skato		movb $'-',%al			# Separator
94243561Skato		cmpb $0x8,%cl			# Half way?
94343561Skato		je dump.6			# Yes
94443561Skato		movb $' ',%al			# Use space
94543561Skatodump.6: 	stosb				# Save separator
94643561Skato		jmp dump.5			# Continue
94786497Snyandump.6a:	decb %dl			# Keep count
94886497Snyan		jz dump.7			# If done
94986497Snyan		movb $0xa,%al			# Line feed
95086497Snyan		stosb				# Save one
95186497Snyan		movb $7,%cl			# Leading
95286497Snyan		movb $' ',%al			#  spaces
95386497Snyandump.6b:	stosb				# Dump
95486497Snyan		decb %cl			#  spaces
95586497Snyan		jnz dump.6b
95686497Snyan		jmp dump.4a			# Next line
95743561Skatodump.7: 	popl %ds			# Restore
95843561Skatodump.8: 	popl %esi			# Restore
95943561Skato		movb $0xa,%al			# Line feed
96043561Skato		testb $DMP_EOL,%ch		# End of line?
96143561Skato		jnz dump.9			# Yes
96243561Skato		movb $' ',%al			# Use spaces
96343561Skato		stosb				# Save one
96443561Skatodump.9: 	jmp dump.0			# Continue
96543561Skatodump.10:	stosb				# Terminate string
96643561Skato		ret				# To caller
967128710Sru/*
968128710Sru * Convert EAX, AX, or AL to hex, saving the result to [EDI].
969128710Sru */
97043561Skatohex32:		pushl %eax			# Save
97143561Skato		shrl $0x10,%eax 		# Do upper
97243561Skato		call hex16			#  16
97343561Skato		popl %eax			# Restore
97443561Skatohex16:		call hex16.1			# Do upper 8
97543561Skatohex16.1:	xchgb %ah,%al			# Save/restore
97643561Skatohex8:		pushl %eax			# Save
97743561Skato		shrb $0x4,%al			# Do upper
97843561Skato		call hex8.1			#  4
97943561Skato		popl %eax			# Restore
98043561Skatohex8.1: 	andb $0xf,%al			# Get lower 4
98143561Skato		cmpb $0xa,%al			# Convert
98243561Skato		sbbb $0x69,%al			#  to hex
98343561Skato		das				#  digit
98443561Skato		orb $0x20,%al			# To lower case
98543561Skato		stosb				# Save char
98643561Skato		ret				# (Recursive)
987128710Sru/*
988128710Sru * Output zero-terminated string [ESI] to the console.
989128710Sru */
99043561Skatoputstr.0:	call putchr			# Output char
99143561Skatoputstr: 	lodsb				# Load char
99243561Skato		testb %al,%al			# End of string?
99343561Skato		jnz putstr.0			# No
99443561Skato		ret				# To caller
995125780Snyan#ifdef BTX_SERIAL
99686497Snyan		.set SIO_PRT,SIOPRT		# Base port
99786497Snyan		.set SIO_FMT,SIOFMT		# 8N1
99886497Snyan		.set SIO_DIV,(115200/SIOSPD)	# 115200 / SPD
99986497Snyan
1000138189Snyan/*
1001128710Sru * void sio_init(void)
1002138189Snyan */
100386497Snyansio_init:	movw $SIO_PRT+0x3,%dx		# Data format reg
100486497Snyan		movb $SIO_FMT|0x80,%al		# Set format
100586497Snyan		outb %al,(%dx)			#  and DLAB
100686497Snyan		pushl %edx			# Save
100786497Snyan		subb $0x3,%dl			# Divisor latch reg
100886497Snyan		movw $SIO_DIV,%ax		# Set
100986497Snyan		outw %ax,(%dx)			#  BPS
101086497Snyan		popl %edx			# Restore
101186497Snyan		movb $SIO_FMT,%al		# Clear
101286497Snyan		outb %al,(%dx)			#  DLAB
101386497Snyan		incl %edx			# Modem control reg
101486497Snyan		movb $0x3,%al			# Set RTS,
101586497Snyan		outb %al,(%dx)			#  DTR
101686497Snyan		incl %edx			# Line status reg
101786497Snyan
1018138189Snyan/*
1019128710Sru * void sio_flush(void)
1020138189Snyan */
102186497Snyansio_flush.0:	call sio_getc.1 		# Get character
102286497Snyansio_flush:	call sio_ischar 		# Check for character
102386497Snyan		jnz sio_flush.0 		# Till none
102486497Snyan		ret				# To caller
102586497Snyan
1026138189Snyan/*
1027128710Sru * void sio_putc(int c)
1028138189Snyan */
102986497Snyansio_putc:	movw $SIO_PRT+0x5,%dx		# Line status reg
103086497Snyan		xor %ecx,%ecx			# Timeout
103186497Snyan		movb $0x40,%ch			#  counter
103286497Snyansio_putc.1:	inb (%dx),%al			# Transmitter
103386497Snyan		testb $0x20,%al 		#  buffer empty?
103486497Snyan		loopz sio_putc.1		# No
103586497Snyan		jz sio_putc.2			# If timeout
103686497Snyan		movb 0x4(%esp,1),%al		# Get character
103786497Snyan		subb $0x5,%dl			# Transmitter hold reg
103886497Snyan		outb %al,(%dx)			# Write character
103986497Snyansio_putc.2:	ret $0x4			# To caller
104086497Snyan
1041138189Snyan/*
1042128710Sru * int sio_getc(void)
1043138189Snyan */
104486497Snyansio_getc:	call sio_ischar 		# Character available?
104586497Snyan		jz sio_getc			# No
104686497Snyansio_getc.1:	subb $0x5,%dl			# Receiver buffer reg
104786497Snyan		inb (%dx),%al			# Read character
104886497Snyan		ret				# To caller
104986497Snyan
1050138189Snyan/*
1051128710Sru * int sio_ischar(void)
1052138189Snyan */
105386497Snyansio_ischar:	movw $SIO_PRT+0x5,%dx		# Line status register
105486497Snyan		xorl %eax,%eax			# Zero
105586497Snyan		inb (%dx),%al			# Received data
105686497Snyan		andb $0x1,%al			#  ready?
105786497Snyan		ret				# To caller
105886497Snyan
1059128710Sru/*
1060128710Sru * Output character AL to the serial console.
1061128710Sru */
106286497Snyanputchr: 	pusha				# Save
106386497Snyan		cmpb $10, %al			# is it a newline?
106486497Snyan		jne putchr.1			#  no?, then leave
106586497Snyan		push $13			# output a carriage
106686497Snyan		call sio_putc			#  return first
106786497Snyan		movb $10, %al			# restore %al
106886497Snyanputchr.1:	pushl %eax			# Push the character
106986497Snyan						#  onto the stack
107086497Snyan		call sio_putc			# Output the character
107186497Snyan		popa				# Restore
107286497Snyan		ret				# To caller
1073125780Snyan#else
1074128710Sru/*
1075128710Sru * Output character AL to the console.
1076128710Sru */
107743561Skatoputchr: 	pusha				# Save
107843561Skato		xorl %ecx,%ecx			# Zero for loops
107943561Skato		movb $SCR_MAT,%ah		# Mode/attribute
108043561Skato		movl $BDA_POS,%ebx		# BDA pointer
108143561Skato		movw (%ebx),%dx 		# Cursor position
108243561Skato		movl $0xa0000,%edi
108343561Skatoputchr.1:	cmpb $0xa,%al			# New line?
108443561Skato		je putchr.2			# Yes
108543561Skato		movw %dx,%cx
108643561Skato		movb %al,(%edi,%ecx,1)		# Write char
108743561Skato		addl $0x2000,%ecx
108843561Skato		movb %ah,(%edi,%ecx,1)		# Write attr
108943561Skato		addw $0x02,%dx
109043561Skato		jmp putchr.3
109143561Skatoputchr.2:	movw %dx,%ax
109243561Skato		movb $SCR_COL*2,%dl
109343561Skato		div %dl
109443561Skato		incb %al
109543561Skato		mul %dl
109643561Skato		movw %ax,%dx
109743561Skatoputchr.3:	cmpw $SCR_ROW*SCR_COL*2,%dx
109843561Skato		jb putchr.4			# No
109943561Skato		leal 2*SCR_COL(%edi),%esi	# New top line
110043561Skato		movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
110143561Skato		rep				# Scroll
110243561Skato		movsl				#  screen
110386497Snyan		movb $0x20,%al			# Space
110443561Skato		xorb %ah,%ah
110543561Skato		movb $SCR_COL,%cl		# Columns to clear
110643561Skato		rep				# Clear
110743561Skato		stosw				#  line
110843561Skato		movw $(SCR_ROW-1)*SCR_COL*2,%dx
110943561Skatoputchr.4:	movw %dx,(%ebx) 		# Update position
111043561Skato		popa				# Restore
111143561Skato		ret				# To caller
1112125780Snyan#endif
111343561Skato
111443561Skato		.p2align 4
1115128710Sru/*
1116128710Sru * Global descriptor table.
1117128710Sru */
111843561Skatogdt:		.word 0x0,0x0,0x0,0x0		# Null entry
111943561Skato		.word 0xffff,0x0,0x9a00,0xcf	# SEL_SCODE
112043561Skato		.word 0xffff,0x0,0x9200,0xcf	# SEL_SDATA
112143561Skato		.word 0xffff,0x0,0x9a00,0x0	# SEL_RCODE
112243561Skato		.word 0xffff,0x0,0x9200,0x0	# SEL_RDATA
112343561Skato		.word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
112443561Skato		.word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
112543561Skato		.word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
112643561Skatogdt.1:
1127128710Sru/*
1128128710Sru * Pseudo-descriptors.
1129128710Sru */
113043561Skatogdtdesc:	.word gdt.1-gdt-1,gdt,0x0	# GDT
113143561Skatoidtdesc:	.word _IDTLM,MEM_IDT,0x0	# IDT
113243561Skatoivtdesc:	.word 0x400-0x0-1,0x0,0x0	# IVT
1133128710Sru/*
1134128710Sru * IDT construction control string.
1135128710Sru */
113643561Skatoidtctl: 	.byte 0x10,  0x8e		# Int 0x0-0xf
113743561Skato		.word 0x7dfb,intx00		#  (exceptions)
113843561Skato		.byte 0x10,  0x8e		# Int 0x10
113943561Skato		.word 0x1,   intx10		#  (exception)
114043561Skato		.byte 0x10,  0x8e		# Int 0x20-0x2f
114143561Skato		.word 0xffff,intx20		#  (hardware)
114243561Skato		.byte 0x1,   0xee		# int 0x30
114343561Skato		.word 0x1,   intx30		#  (system call)
114443561Skato		.byte 0x2,   0xee		# Int 0x31-0x32
114543561Skato		.word 0x1,   intx31		#  (V86, null)
114643561Skato		.byte 0x0			# End of string
1147128710Sru/*
1148128710Sru * Dump format string.
1149128710Sru */
115043561Skatodmpfmt: 	.byte '\n'			# "\n"
115143561Skato		.ascii "int"			# "int="
115243561Skato		.byte 0x80|DMP_X32,	   0x40 # "00000000  "
115343561Skato		.ascii "err"			# "err="
115443561Skato		.byte 0x80|DMP_X32,	   0x44 # "00000000  "
115543561Skato		.ascii "efl"			# "efl="
115643561Skato		.byte 0x80|DMP_X32,	   0x50 # "00000000  "
115743561Skato		.ascii "eip"			# "eip="
115843561Skato		.byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
115943561Skato		.ascii "eax"			# "eax="
116043561Skato		.byte 0x80|DMP_X32,	   0x34 # "00000000  "
116143561Skato		.ascii "ebx"			# "ebx="
116243561Skato		.byte 0x80|DMP_X32,	   0x28 # "00000000  "
116343561Skato		.ascii "ecx"			# "ecx="
116443561Skato		.byte 0x80|DMP_X32,	   0x30 # "00000000  "
116543561Skato		.ascii "edx"			# "edx="
116643561Skato		.byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
116743561Skato		.ascii "esi"			# "esi="
116843561Skato		.byte 0x80|DMP_X32,	   0x1c # "00000000  "
116943561Skato		.ascii "edi"			# "edi="
117043561Skato		.byte 0x80|DMP_X32,	   0x18 # "00000000  "
117143561Skato		.ascii "ebp"			# "ebp="
117243561Skato		.byte 0x80|DMP_X32,	   0x20 # "00000000  "
117343561Skato		.ascii "esp"			# "esp="
117443561Skato		.byte 0x80|DMP_X32|DMP_EOL,0x0	# "00000000\n"
117543561Skato		.ascii "cs"			# "cs="
117643561Skato		.byte 0x80|DMP_X16,	   0x4c # "0000  "
117743561Skato		.ascii "ds"			# "ds="
117843561Skato		.byte 0x80|DMP_X16,	   0xc	# "0000  "
117943561Skato		.ascii "es"			# "es="
118043561Skato		.byte 0x80|DMP_X16,	   0x8	# "0000  "
118143561Skato		.ascii "  "			# "  "
118243561Skato		.ascii "fs"			# "fs="
118343561Skato		.byte 0x80|DMP_X16,	   0x10 # "0000  "
118443561Skato		.ascii "gs"			# "gs="
118543561Skato		.byte 0x80|DMP_X16,	   0x14 # "0000  "
118643561Skato		.ascii "ss"			# "ss="
118743561Skato		.byte 0x80|DMP_X16|DMP_EOL,0x4	# "0000\n"
118843561Skato		.ascii "cs:eip" 		# "cs:eip="
118943561Skato		.byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
119043561Skato		.ascii "ss:esp" 		# "ss:esp="
119143561Skato		.byte 0x80|DMP_MEM|DMP_EOL,0x0	# "00 00 ... 00 00\n"
119286497Snyan		.asciz "BTX halted\n"		# End
1193128710Sru/*
1194128710Sru * End of BTX memory.
1195128710Sru */
119643561Skato		.p2align 4
119743561Skatobreak:
1198