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: stable/11/stand/pc98/btx/btx/btx.S 249846 2013-04-24 17:20:45Z dim $
16128710Sru */
1743561Skato
18235264Savg#include <bootargs.h>
19235264Savg
20128710Sru/*
21128710Sru * Memory layout.
22128710Sru */
2343561Skato		.set MEM_BTX,0x1000		# Start of BTX memory
2443561Skato		.set MEM_ESP0,0x1800		# Supervisor stack
2543561Skato		.set MEM_BUF,0x1800		# Scratch buffer
26200254Snyan		.set MEM_ESPR,0x5e00		# Real mode stack
27200254Snyan		.set MEM_IDT,0x5e00		# IDT
28200254Snyan		.set MEM_TSS,0x5f98		# TSS
29200254Snyan		.set MEM_MAP,0x6000		# I/O bit map
30200254Snyan		.set MEM_TSS_END,0x7fff		# End of TSS
3143561Skato		.set MEM_ORG,0x9000		# BTX code
3243561Skato		.set MEM_USR,0xa000		# Start of user memory
33128710Sru/*
34128710Sru * Paging control.
35128710Sru */
3643561Skato		.set PAG_SIZ,0x1000		# Page size
3743561Skato		.set PAG_CNT,0x1000		# Pages to map
38128710Sru/*
39200254Snyan * Fields in %eflags.
40200254Snyan */
41200254Snyan		.set PSL_RESERVED_DEFAULT,0x00000002
42200254Snyan		.set PSL_T,0x00000100		# Trap flag
43200254Snyan		.set PSL_I,0x00000200		# Interrupt enable flag
44200254Snyan		.set PSL_VM,0x00020000		# Virtual 8086 mode flag
45200254Snyan		.set PSL_AC,0x00040000		# Alignment check flag
46200254Snyan/*
47128710Sru * Segment selectors.
48128710Sru */
4943561Skato		.set SEL_SCODE,0x8		# Supervisor code
5043561Skato		.set SEL_SDATA,0x10		# Supervisor data
5143561Skato		.set SEL_RCODE,0x18		# Real mode code
5243561Skato		.set SEL_RDATA,0x20		# Real mode data
5343561Skato		.set SEL_UCODE,0x28|3		# User code
5443561Skato		.set SEL_UDATA,0x30|3		# User data
5543561Skato		.set SEL_TSS,0x38		# TSS
56128710Sru/*
57128710Sru * Task state segment fields.
58128710Sru */
5943561Skato		.set TSS_ESP0,0x4		# PL 0 ESP
6043561Skato		.set TSS_SS0,0x8		# PL 0 SS
6143561Skato		.set TSS_MAP,0x66		# I/O bit map base
62128710Sru/*
63128710Sru * System calls.
64128710Sru */
6543561Skato		.set SYS_EXIT,0x0		# Exit
6643561Skato		.set SYS_EXEC,0x1		# Exec
67128710Sru/*
68200254Snyan * Fields in V86 interface structure.
69128710Sru */
70200254Snyan		.set V86_CTL,0x0		# Control flags
71200254Snyan		.set V86_ADDR,0x4		# Int number/address
72200254Snyan		.set V86_ES,0x8			# V86 ES
73200254Snyan		.set V86_DS,0xc			# V86 DS
74200254Snyan		.set V86_FS,0x10		# V86 FS
75200254Snyan		.set V86_GS,0x14		# V86 GS
76128710Sru/*
77200254Snyan * V86 control flags.
78200254Snyan */
79200254Snyan		.set V86F_ADDR,0x10000		# Segment:offset address
80200254Snyan		.set V86F_CALLF,0x20000		# Emulate far call
81200254Snyan		.set V86F_FLAGS,0x40000		# Return flags
82200254Snyan/*
83128710Sru * Dump format control bytes.
84128710Sru */
8543561Skato		.set DMP_X16,0x1		# Word
8643561Skato		.set DMP_X32,0x2		# Long
8743561Skato		.set DMP_MEM,0x4		# Memory
8843561Skato		.set DMP_EOL,0x8		# End of line
89128710Sru/*
90128710Sru * Screen defaults and assumptions.
91128710Sru */
9243561Skato		.set SCR_MAT,0xe1		# Mode/attribute
9343561Skato		.set SCR_COL,0x50		# Columns per row
9443561Skato		.set SCR_ROW,0x19		# Rows per screen
95128710Sru/*
96128710Sru * BIOS Data Area locations.
97128710Sru */
9858871Skato		.set BDA_MEM,0x501		# Free memory
9958871Skato		.set BDA_POS,0x53e		# Cursor position
100128710Sru/*
101128710Sru * Derivations, for brevity.
102128710Sru */
10343561Skato		.set _ESP0H,MEM_ESP0>>0x8	# Byte 1 of ESP0
10443561Skato		.set _TSSIO,MEM_MAP-MEM_TSS	# TSS I/O base
105176645Snyan		.set _TSSLM,MEM_TSS_END-MEM_TSS	# TSS limit
10643561Skato		.set _IDTLM,MEM_TSS-MEM_IDT-1	# IDT limit
107128710Sru/*
108128710Sru * Code segment.
109128710Sru */
11043561Skato		.globl start
11161064Snyan		.code16
11243561Skatostart:						# Start of code
113128710Sru/*
114128710Sru * BTX header.
115128710Sru */
11643561Skatobtx_hdr:	.byte 0xeb			# Machine ID
11743561Skato		.byte 0xe			# Header size
11843561Skato		.ascii "BTX"			# Magic
11943561Skato		.byte 0x1			# Major version
120200254Snyan		.byte 0x2			# Minor version
12168358Snyan		.byte BTX_FLAGS			# Flags
12243561Skato		.word PAG_CNT-MEM_ORG>>0xc	# Paging control
12343561Skato		.word break-start		# Text size
12443561Skato		.long 0x0			# Entry address
125128710Sru/*
126128710Sru * Initialization routine.
127128710Sru */
12843561Skatoinit:		cli				# Disable interrupts
12961064Snyan		xor %ax,%ax			# Zero/segment
13061064Snyan		mov %ax,%ss			# Set up
13161064Snyan		mov $MEM_ESP0,%sp		#  stack
13261064Snyan		mov %ax,%es			# Address
13361064Snyan		mov %ax,%ds			#  data
13461064Snyan		pushl $0x2			# Clear
13561064Snyan		popfl				#  flags
136128710Sru/*
137128710Sru * Initialize memory.
138128710Sru */
13961064Snyan		mov $MEM_IDT,%di		# Memory to initialize
14061064Snyan		mov $(MEM_ORG-MEM_IDT)/2,%cx	# Words to zero
14143561Skato		rep				# Zero-fill
14261064Snyan		stosw				#  memory
143128710Sru/*
144200254Snyan * Update real mode IDT for reflecting hardware interrupts.
145200254Snyan */
146200254Snyan		mov $intr20,%bx			# Address first handler
147200254Snyan		mov $0x10,%cx			# Number of handlers
148200254Snyan		mov $0x20*4,%di			# First real mode IDT entry
149200254Snyaninit.0:		mov %bx,(%di)			# Store IP
150200254Snyan		inc %di				# Address next
151200254Snyan		inc %di				#  entry
152200254Snyan		stosw				# Store CS
153200254Snyan		add $4,%bx			# Next handler
154200254Snyan		loop init.0			# Next IRQ
155200254Snyan/*
156128710Sru * Create IDT.
157128710Sru */
158200254Snyan		mov $MEM_IDT,%di
15961064Snyan		mov $idtctl,%si			# Control string
16043561Skatoinit.1: 	lodsb				# Get entry
16161064Snyan		cbw				#  count
16261064Snyan		xchg %ax,%cx			#  as word
16361064Snyan		jcxz init.4			# If done
16443561Skato		lodsb				# Get segment
16561064Snyan		xchg %ax,%dx	 		#  P:DPL:type
16661064Snyan		lodsw				# Get control
16761064Snyan		xchg %ax,%bx			#  set
16861064Snyan		lodsw				# Get handler offset
16961064Snyan		mov $SEL_SCODE,%dh		# Segment selector
17061064Snyaninit.2: 	shr %bx				# Handle this int?
17143561Skato		jnc init.3			# No
17261064Snyan		mov %ax,(%di)			# Set handler offset
17361064Snyan		mov %dh,0x2(%di)		#  and selector
17461064Snyan		mov %dl,0x5(%di)		# Set P:DPL:type
17561064Snyan		add $0x4,%ax			# Next handler
17661064Snyaninit.3: 	lea 0x8(%di),%di		# Next entry
17743561Skato		loop init.2			# Till set done
17843561Skato		jmp init.1			# Continue
179128710Sru/*
180128710Sru * Initialize TSS.
181128710Sru */
18261064Snyaninit.4: 	movb $_ESP0H,TSS_ESP0+1(%di)	# Set ESP0
18361064Snyan		movb $SEL_SDATA,TSS_SS0(%di)	# Set SS0
18461064Snyan		movb $_TSSIO,TSS_MAP(%di)	# Set I/O bit map base
185128710Sru/*
186128710Sru * Bring up the system.
187128710Sru */
18861064Snyan		mov $0x2820,%bx			# Set protected mode
18961064Snyan		callw setpic			#  IRQ offsets
19061064Snyan		lidt idtdesc	 		# Set IDT
19161064Snyan		lgdt gdtdesc	 		# Set GDT
19261064Snyan		mov %cr0,%eax			# Switch to protected
193164114Snyan		inc %ax				#  mode
194128710Sru		mov %eax,%cr0			#
19561064Snyan		ljmp $SEL_SCODE,$init.8		# To 32-bit code
19661064Snyan		.code32
19743561Skatoinit.8: 	xorl %ecx,%ecx			# Zero
19843561Skato		movb $SEL_SDATA,%cl		# To 32-bit
19961064Snyan		movw %cx,%ss			#  stack
200128710Sru/*
201128710Sru * Launch user task.
202128710Sru */
20343561Skato		movb $SEL_TSS,%cl		# Set task
20461064Snyan		ltr %cx				#  register
20543561Skato		movl $MEM_USR,%edx		# User base address
20643561Skato		movzwl %ss:BDA_MEM,%eax 	# Get free memory
20743561Skato		andl $0x7,%eax
20843561Skato		incl %eax
20943561Skato		shll $0x11,%eax			# To bytes
210235264Savg		subl $ARGSPACE,%eax		# Less arg space
21143561Skato		subl %edx,%eax			# Less base
21243561Skato		movb $SEL_UDATA,%cl		# User data selector
21343561Skato		pushl %ecx			# Set SS
21443561Skato		pushl %eax			# Set ESP
21561064Snyan		push $0x202			# Set flags (IF set)
21661064Snyan		push $SEL_UCODE			# Set CS
21743561Skato		pushl btx_hdr+0xc		# Set EIP
21843561Skato		pushl %ecx			# Set GS
21943561Skato		pushl %ecx			# Set FS
22043561Skato		pushl %ecx			# Set DS
22143561Skato		pushl %ecx			# Set ES
22243561Skato		pushl %edx			# Set EAX
22343561Skato		movb $0x7,%cl			# Set remaining
22461064Snyaninit.9:		push $0x0			#  general
22543561Skato		loop init.9			#  registers
226125780Snyan#ifdef BTX_SERIAL
22786497Snyan		call sio_init			# setup the serial console
228125780Snyan#endif
22943561Skato		popa				#  and initialize
23043561Skato		popl %es			# Initialize
23143561Skato		popl %ds			#  user
23243561Skato		popl %fs			#  segment
23343561Skato		popl %gs			#  registers
23443561Skato		iret				# To user mode
235128710Sru/*
236128710Sru * Exit routine.
237128710Sru */
23843561Skatoexit:		cli				# Disable interrupts
23943561Skato		movl $MEM_ESP0,%esp		# Clear stack
240128710Sru/*
241128710Sru * Turn off paging.
242128710Sru */
24343561Skato		movl %cr0,%eax			# Get CR0
24443561Skato		andl $~0x80000000,%eax		# Disable
24543561Skato		movl %eax,%cr0			#  paging
24643561Skato		xorl %ecx,%ecx			# Zero
24743561Skato		movl %ecx,%cr3			# Flush TLB
248128710Sru/*
249128710Sru * Restore the GDT in case we caught a kernel trap.
250128710Sru */
251249846Sdim		lgdt %cs:gdtdesc		# Set GDT
252128710Sru/*
253128710Sru * To 16 bits.
254128710Sru */
25561064Snyan		ljmpw $SEL_RCODE,$exit.1	# Reload CS
25661064Snyan		.code16
25761064Snyanexit.1: 	mov $SEL_RDATA,%cl		# 16-bit selector
25861064Snyan		mov %cx,%ss			# Reload SS
25961064Snyan		mov %cx,%ds			# Load
26061064Snyan		mov %cx,%es			#  remaining
26161064Snyan		mov %cx,%fs			#  segment
26261064Snyan		mov %cx,%gs			#  registers
263128710Sru/*
264128710Sru * To real-address mode.
265128710Sru */
26661064Snyan		dec %ax				# Switch to
26761064Snyan		mov %eax,%cr0			#  real mode
26861064Snyan		ljmp $0x0,$exit.2		# Reload CS
26961064Snyanexit.2: 	xor %ax,%ax			# Real mode segment
27061064Snyan		mov %ax,%ss			# Reload SS
27161064Snyan		mov %ax,%ds			# Address data
27261064Snyan		mov $0x1008,%bx			# Set real mode
27361064Snyan		callw setpic			#  IRQ offsets
27461064Snyan		lidt ivtdesc	 		# Set IVT
275128710Sru/*
276128710Sru * Reboot or await reset.
277128710Sru */
27843561Skato		sti				# Enable interrupts
27961064Snyan		testb $0x1,btx_hdr+0x7		# Reboot?
28043561Skatoexit.3:		jz exit.3			# No
28143561Skato		movb $0xa0,%al
28243561Skato		outb %al,$0x35
283200254Snyan		movb $0x00,%al
284200254Snyan		outb %al,$0xf0			# reboot the machine
28543561Skatoexit.4:		jmp exit.4
286128710Sru/*
287128710Sru * Set IRQ offsets by reprogramming 8259A PICs.
288128710Sru */
28961064Snyansetpic: 	in $0x02,%al			# Save master
29061064Snyan		push %ax			#  IMR
29161064Snyan		in $0x0a,%al			# Save slave
29261064Snyan		push %ax			#  IMR
29343561Skato		movb $0x11,%al			# ICW1 to
29443561Skato		outb %al,$0x00			#  master,
29543561Skato		outb %al,$0x08			#  slave
29643561Skato		movb %bl,%al			# ICW2 to
29743561Skato		outb %al,$0x02			#  master
29843561Skato		movb %bh,%al			# ICW2 to
29943561Skato		outb %al,$0x0a			#  slave
30043561Skato		movb $0x80,%al			# ICW3 to
30143561Skato		outb %al,$0x02			#  master
30243561Skato		movb $0x7,%al			# ICW3 to
30343561Skato		outb %al,$0x0a			#  slave
30443561Skato		movb $0x1d,%al			# ICW4 to
30543561Skato		outb %al,$0x02			#  master,
30643561Skato		movb $0x9,%al			# ICW4 to
30743561Skato		outb %al,$0x0a			#  slave
30861064Snyan		pop %ax				# Restore slave
30943561Skato		outb %al,$0x0a			#  IMR
31061064Snyan		pop %ax				# Restore master
31143561Skato		outb %al,$0x02			#  IMR
31261064Snyan		retw				# To caller
31361064Snyan		.code32
314128710Sru/*
315128710Sru * Exception jump table.
316128710Sru */
31761064Snyanintx00: 	push $0x0			# Int 0x0: #DE
31843561Skato		jmp ex_noc			# Divide error
31961064Snyan		push $0x1			# Int 0x1: #DB
32043561Skato		jmp ex_noc			# Debug
32161064Snyan		push $0x3			# Int 0x3: #BP
32243561Skato		jmp ex_noc			# Breakpoint
32361064Snyan		push $0x4			# Int 0x4: #OF
32443561Skato		jmp ex_noc			# Overflow
32561064Snyan		push $0x5			# Int 0x5: #BR
32643561Skato		jmp ex_noc			# BOUND range exceeded
32761064Snyan		push $0x6			# Int 0x6: #UD
32843561Skato		jmp ex_noc			# Invalid opcode
32961064Snyan		push $0x7			# Int 0x7: #NM
33043561Skato		jmp ex_noc			# Device not available
33161064Snyan		push $0x8			# Int 0x8: #DF
33243561Skato		jmp except			# Double fault
33361064Snyan		push $0xa			# Int 0xa: #TS
33443561Skato		jmp except			# Invalid TSS
33561064Snyan		push $0xb			# Int 0xb: #NP
33643561Skato		jmp except			# Segment not present
33761064Snyan		push $0xc			# Int 0xc: #SS
33843561Skato		jmp except			# Stack segment fault
33961064Snyan		push $0xd			# Int 0xd: #GP
340200254Snyan		jmp except			# General protection
34161064Snyan		push $0xe			# Int 0xe: #PF
34243561Skato		jmp except			# Page fault
34361064Snyanintx10: 	push $0x10			# Int 0x10: #MF
34443561Skato		jmp ex_noc			# Floating-point error
345128710Sru/*
346128710Sru * Save a zero error code.
347128710Sru */
34843561Skatoex_noc: 	pushl (%esp,1)			# Duplicate int no
34943561Skato		movb $0x0,0x4(%esp,1)		# Fake error code
350128710Sru/*
351128710Sru * Handle exception.
352128710Sru */
35343561Skatoexcept: 	cld				# String ops inc
35443561Skato		pushl %ds			# Save
35543561Skato		pushl %es			#  most
35643561Skato		pusha				#  registers
35743561Skato		pushl %gs			# Set GS
35843561Skato		pushl %fs			# Set FS
35943561Skato		pushl %ds			# Set DS
36043561Skato		pushl %es			# Set ES
36143561Skato		cmpw $SEL_SCODE,0x44(%esp,1)	# Supervisor mode?
36243561Skato		jne except.1			# No
36343561Skato		pushl %ss			# Set SS
36443561Skato		jmp except.2			# Join common code
365200254Snyanexcept.1:	pushl 0x50(%esp,1)		# Set SS
366200254Snyanexcept.2:	pushl 0x50(%esp,1)		# Set ESP
367200254Snyan		push $SEL_SDATA			# Set up
36843561Skato		popl %ds			#  to
36943561Skato		pushl %ds			#  address
37043561Skato		popl %es			#  data
37143561Skato		movl %esp,%ebx			# Stack frame
37243561Skato		movl $dmpfmt,%esi		# Dump format string
37343561Skato		movl $MEM_BUF,%edi		# Buffer
37443561Skato		pushl %eax
37543561Skato		pushl %edx
376200254Snyanwait.1:		inb  $0x60,%al
37743561Skato		testb $0x04,%al
37843561Skato		jz   wait.1
37943561Skato		movb $0xe0,%al
38043561Skato		outb %al,$0x62
381200254Snyanwait.2:		inb  $0x60,%al
38243561Skato		testb $0x01,%al
38343561Skato		jz   wait.2
38443561Skato		xorl %edx,%edx
38543561Skato		inb  $0x62,%al
38643561Skato		movb %al,%dl
38743561Skato		inb  $0x62,%al
38843561Skato		movb %al,%dh
38943561Skato		inb  $0x62,%al
39043561Skato		inb  $0x62,%al
39143561Skato		inb  $0x62,%al
39243561Skato		movl %edx,%eax
39343561Skato		shlw $1,%ax
39443561Skato		movl $BDA_POS,%edx
39543561Skato		movw %ax,(%edx)
39643561Skato		popl  %edx
39743561Skato		popl  %eax
39843561Skato		pushl %edi			# Dump to
39943561Skato		call dump			#  buffer
40043561Skato		popl %esi			#  and
40143561Skato		call putstr			#  display
40243561Skato		leal 0x18(%esp,1),%esp		# Discard frame
40343561Skato		popa				# Restore
40443561Skato		popl %es			#  registers
40543561Skato		popl %ds			#  saved
40643561Skato		cmpb $0x3,(%esp,1)		# Breakpoint?
40743561Skato		je except.3			# Yes
40886497Snyan		cmpb $0x1,(%esp,1)		# Debug?
40986497Snyan		jne except.2a			# No
410200254Snyan		testl $PSL_T,0x10(%esp,1)	# Trap flag set?
41186497Snyan		jnz except.3			# Yes
41286497Snyanexcept.2a:	jmp exit			# Exit
41343561Skatoexcept.3:	leal 0x8(%esp,1),%esp		# Discard err, int no
41443561Skato		iret				# From interrupt
41552202Skato
416128710Sru/*
417128710Sru * Reboot the machine by setting the reboot flag and exiting
418128710Sru */
41958871Skatoreboot:		orb $0x1,btx_hdr+0x7		# Set the reboot flag
42058871Skato		jmp exit			# Terminate BTX and reboot
42158871Skato
422128710Sru/*
423200254Snyan * Protected Mode Hardware interrupt jump table.
424128710Sru */
42561064Snyanintx20: 	push $0x8			# Int 0x20: IRQ0
42643561Skato		jmp int_hw			# V86 int 0x8
42761064Snyan		push $0x9			# Int 0x21: IRQ1
42843561Skato		jmp int_hw			# V86 int 0x9
42961064Snyan		push $0xa			# Int 0x22: IRQ2
43043561Skato		jmp int_hw			# V86 int 0xa
43161064Snyan		push $0xb			# Int 0x23: IRQ3
43243561Skato		jmp int_hw			# V86 int 0xb
43361064Snyan		push $0xc			# Int 0x24: IRQ4
43443561Skato		jmp int_hw			# V86 int 0xc
43561064Snyan		push $0xd			# Int 0x25: IRQ5
43643561Skato		jmp int_hw			# V86 int 0xd
43761064Snyan		push $0xe			# Int 0x26: IRQ6
43843561Skato		jmp int_hw			# V86 int 0xe
43961064Snyan		push $0xf			# Int 0x27: IRQ7
44043561Skato		jmp int_hw			# V86 int 0xf
44161064Snyan		push $0x10			# Int 0x28: IRQ8
44243561Skato		jmp int_hw			# V86 int 0x10
44361064Snyan		push $0x11			# Int 0x29: IRQ9
44443561Skato		jmp int_hw			# V86 int 0x11
44561064Snyan		push $0x12			# Int 0x2a: IRQ10
44643561Skato		jmp int_hw			# V86 int 0x12
44761064Snyan		push $0x13			# Int 0x2b: IRQ11
44843561Skato		jmp int_hw			# V86 int 0x13
44961064Snyan		push $0x14			# Int 0x2c: IRQ12
45043561Skato		jmp int_hw			# V86 int 0x14
45161064Snyan		push $0x15			# Int 0x2d: IRQ13
45243561Skato		jmp int_hw			# V86 int 0x15
45361064Snyan		push $0x16			# Int 0x2e: IRQ14
45443561Skato		jmp int_hw			# V86 int 0x16
45561064Snyan		push $0x17			# Int 0x2f: IRQ15
45643561Skato		jmp int_hw			# V86 int 0x17
457200254Snyan
458128710Sru/*
459200254Snyan * Invoke real mode interrupt/function call from user mode with arguments.
460128710Sru */
461200254Snyanintx31: 	pushl $-1			# Dummy int no for btx_v86
462128710Sru/*
463200254Snyan * Invoke real mode interrupt/function call from protected mode.
464200254Snyan *
465200254Snyan * We place a trampoline on the user stack that will return to rret_tramp
466200254Snyan * which will reenter protected mode and then finally return to the user
467200254Snyan * client.
468200254Snyan *
469200254Snyan * Kernel frame %esi points to:		Real mode stack frame at MEM_ESPR:
470200254Snyan *
471200254Snyan * -0x00 user %ss			-0x04 kernel %esp (with full frame)
472200254Snyan * -0x04 user %esp			-0x08 btx_v86 pointer
473200254Snyan * -0x08 user %eflags			-0x0c flags (only used if interrupt)
474200254Snyan * -0x0c user %cs			-0x10 real mode CS:IP return trampoline
475200254Snyan * -0x10 user %eip			-0x12 real mode flags
476200254Snyan * -0x14 int no				-0x16 real mode CS:IP (target)
477200254Snyan * -0x18 %eax
478200254Snyan * -0x1c %ecx
479200254Snyan * -0x20 %edx
480200254Snyan * -0x24 %ebx
481200254Snyan * -0x28 %esp
482200254Snyan * -0x2c %ebp
483200254Snyan * -0x30 %esi
484200254Snyan * -0x34 %edi
485200254Snyan * -0x38 %gs
486200254Snyan * -0x3c %fs
487200254Snyan * -0x40 %ds
488200254Snyan * -0x44 %es
489200254Snyan * -0x48 zero %eax (hardware int only)
490200254Snyan * -0x4c zero %ecx (hardware int only)
491200254Snyan * -0x50 zero %edx (hardware int only)
492200254Snyan * -0x54 zero %ebx (hardware int only)
493200254Snyan * -0x58 zero %esp (hardware int only)
494200254Snyan * -0x5c zero %ebp (hardware int only)
495200254Snyan * -0x60 zero %esi (hardware int only)
496200254Snyan * -0x64 zero %edi (hardware int only)
497200254Snyan * -0x68 zero %gs (hardware int only)
498200254Snyan * -0x6c zero %fs (hardware int only)
499200254Snyan * -0x70 zero %ds (hardware int only)
500200254Snyan * -0x74 zero %es (hardware int only)
501128710Sru */
502200254Snyanint_hw: 	cld				# String ops inc
503200254Snyan		pusha				# Save gp regs
50443561Skato		pushl %gs			# Save
505200254Snyan		pushl %fs			#  seg
506200254Snyan		pushl %ds			#  regs
507200254Snyan		pushl %es
50861064Snyan		push $SEL_SDATA			# Set up
50943561Skato		popl %ds			#  to
51043561Skato		pushl %ds			#  address
51143561Skato		popl %es			#  data
512200254Snyan		leal 0x44(%esp,1),%esi		# Base of frame
513200254Snyan		movl %esp,MEM_ESPR-0x04		# Save kernel stack pointer
514200254Snyan		movl -0x14(%esi),%eax		# Get Int no
515200254Snyan		cmpl $-1,%eax			# Hardware interrupt?
516200254Snyan		jne intusr.1			# Yes
517200254Snyan/*
518200254Snyan * v86 calls save the btx_v86 pointer on the real mode stack and read
519200254Snyan * the address and flags from the btx_v86 structure.  For interrupt
520200254Snyan * handler invocations (VM86 INTx requests), disable interrupts,
521200254Snyan * tracing, and alignment checking while the handler runs.
522200254Snyan */
52343561Skato		movl $MEM_USR,%ebx		# User base
52443561Skato		movl %ebx,%edx			#  address
52543561Skato		addl -0x4(%esi),%ebx		# User ESP
52643561Skato		movl (%ebx),%ebp		# btx_v86 pointer
52743561Skato		addl %ebp,%edx			# Flatten btx_v86 ptr
528200254Snyan		movl %edx,MEM_ESPR-0x08		# Save btx_v86 ptr
529200254Snyan		movl V86_ADDR(%edx),%eax	# Get int no/address
530200254Snyan		movl V86_CTL(%edx),%edx		# Get control flags
531200254Snyan		movl -0x08(%esi),%ebx		# Save user flags in %ebx
532200254Snyan		testl $V86F_ADDR,%edx		# Segment:offset?
533200254Snyan		jnz intusr.4			# Yes
534200254Snyan		andl $~(PSL_I|PSL_T|PSL_AC),%ebx # Disable interrupts, tracing,
535200254Snyan						#  and alignment checking for
536200254Snyan						#  interrupt handler
537200254Snyan		jmp intusr.3			# Skip hardware interrupt
538200254Snyan/*
539200254Snyan * Hardware interrupts store a NULL btx_v86 pointer and use the
540200254Snyan * address (interrupt number) from the stack with empty flags.  Also,
541200254Snyan * push a dummy frame of zeros onto the stack for all the general
542200254Snyan * purpose and segment registers and clear %eflags.  This gives the
543200254Snyan * hardware interrupt handler a clean slate.
544200254Snyan */
545200254Snyanintusr.1:	xorl %edx,%edx			# Control flags
546200254Snyan		movl %edx,MEM_ESPR-0x08		# NULL btx_v86 ptr
547200254Snyan		movl $12,%ecx			# Frame is 12 dwords
548200254Snyanintusr.2:	pushl $0x0			# Fill frame
549200254Snyan		loop intusr.2			#  with zeros
550200254Snyan		movl $PSL_RESERVED_DEFAULT,%ebx # Set clean %eflags
551200254Snyan/*
552200254Snyan * Look up real mode IDT entry for hardware interrupts and VM86 INTx
553200254Snyan * requests.
554200254Snyan */
555200254Snyanintusr.3:	shll $0x2,%eax			# Scale
55643561Skato		movl (%eax),%eax		# Load int vector
557200254Snyan		jmp intusr.5			# Skip CALLF test
558128710Sru/*
559200254Snyan * Panic if V86F_CALLF isn't set with V86F_ADDR.
560200254Snyan */
561200254Snyanintusr.4:	testl $V86F_CALLF,%edx		# Far call?
562200254Snyan		jnz intusr.5			# Ok
563200254Snyan		movl %edx,0x30(%esp,1)		# Place VM86 flags in int no
564200254Snyan		movl $badvm86,%esi		# Display bad
565200254Snyan		call putstr			#  VM86 call
566200254Snyan		popl %es			# Restore
567200254Snyan		popl %ds			#  seg
568200254Snyan		popl %fs			#  regs
569200254Snyan		popl %gs
570200254Snyan		popal				# Restore gp regs
571200254Snyan		jmp ex_noc			# Panic
572200254Snyan/*
573200254Snyan * %eax now holds the segment:offset of the function.
574200254Snyan * %ebx now holds the %eflags to pass to real mode.
575200254Snyan * %edx now holds the V86F_* flags.
576200254Snyan */
577200254Snyanintusr.5:	movw %bx,MEM_ESPR-0x12		# Pass user flags to real mode
578200254Snyan						#  target
579200254Snyan/*
580200254Snyan * If this is a v86 call, copy the seg regs out of the btx_v86 structure.
581200254Snyan */
582200254Snyan		movl MEM_ESPR-0x08,%ecx		# Get btx_v86 ptr
583200254Snyan		jecxz intusr.6			# Skip for hardware ints
584200254Snyan		leal -0x44(%esi),%edi		# %edi => kernel stack seg regs
585200254Snyan		pushl %esi			# Save
586200254Snyan		leal V86_ES(%ecx),%esi		# %esi => btx_v86 seg regs
587200254Snyan		movl $4,%ecx			# Copy seg regs
588200254Snyan		rep				#  from btx_v86
589200254Snyan		movsl				#  to kernel stack
590200254Snyan		popl %esi			# Restore
591200254Snyanintusr.6:	movl -0x08(%esi),%ebx		# Copy user flags to real
592200254Snyan		movl %ebx,MEM_ESPR-0x0c		#  mode return trampoline
593200254Snyan		movl $rret_tramp,%ebx		# Set return trampoline
594200254Snyan		movl %ebx,MEM_ESPR-0x10		#  CS:IP
595200254Snyan		movl %eax,MEM_ESPR-0x16		# Real mode target CS:IP
596200254Snyan		ljmpw $SEL_RCODE,$intusr.7	# Change to 16-bit segment
597200254Snyan		.code16
598200254Snyanintusr.7:	movl %cr0,%eax			# Leave
599200254Snyan		dec %al				#  protected
600200254Snyan		movl %eax,%cr0			#  mode
601200254Snyan		ljmpw $0x0,$intusr.8
602200254Snyanintusr.8:	xorw %ax,%ax			# Reset %ds
603200254Snyan		movw %ax,%ds			#  and
604200254Snyan		movw %ax,%ss			#  %ss
605200254Snyan		lidt ivtdesc	 		# Set IVT
606200254Snyan		popl %es			# Restore
607200254Snyan		popl %ds			#  seg
608200254Snyan		popl %fs			#  regs
609200254Snyan		popl %gs
610200254Snyan		popal				# Restore gp regs
611200254Snyan		movw $MEM_ESPR-0x16,%sp		# Switch to real mode stack
612200254Snyan		iret				# Call target routine
613200254Snyan/*
614200254Snyan * For the return to real mode we setup a stack frame like this on the real
615200254Snyan * mode stack.  Note that callf calls won't pop off the flags, but we just
616200254Snyan * ignore that by repositioning %sp to be just above the btx_v86 pointer
617200254Snyan * so it is aligned.  The stack is relative to MEM_ESPR.
618200254Snyan *
619200254Snyan * -0x04	kernel %esp
620200254Snyan * -0x08	btx_v86
621200254Snyan * -0x0c	%eax
622200254Snyan * -0x10	%ecx
623200254Snyan * -0x14	%edx
624200254Snyan * -0x18	%ebx
625200254Snyan * -0x1c	%esp
626200254Snyan * -0x20	%ebp
627200254Snyan * -0x24	%esi
628200254Snyan * -0x28	%edi
629200254Snyan * -0x2c	%gs
630200254Snyan * -0x30	%fs
631200254Snyan * -0x34	%ds
632200254Snyan * -0x38	%es
633200254Snyan * -0x3c	%eflags
634200254Snyan */
635200254Snyanrret_tramp:	movw $MEM_ESPR-0x08,%sp		# Reset stack pointer
636200254Snyan		pushal				# Save gp regs
637200254Snyan		pushl %gs			# Save
638200254Snyan		pushl %fs			#  seg
639200254Snyan		pushl %ds			#  regs
640200254Snyan		pushl %es
641200254Snyan		pushfl				# Save %eflags
642200254Snyan		cli				# Disable interrupts
643200254Snyan		std				# String ops dec
644200254Snyan		xorw %ax,%ax			# Reset seg
645200254Snyan		movw %ax,%ds			#  regs
646200254Snyan		movw %ax,%es			#  (%ss is already 0)
647200254Snyan		lidt idtdesc	 		# Set IDT
648200254Snyan		lgdt gdtdesc	 		# Set GDT
649200254Snyan		mov %cr0,%eax			# Switch to protected
650200254Snyan		inc %ax				#  mode
651200254Snyan		mov %eax,%cr0			#
652200254Snyan		ljmp $SEL_SCODE,$rret_tramp.1	# To 32-bit code
653200254Snyan		.code32
654200254Snyanrret_tramp.1:	xorl %ecx,%ecx			# Zero
655200254Snyan		movb $SEL_SDATA,%cl		# Setup
656200254Snyan		movw %cx,%ss			#  32-bit
657200254Snyan		movw %cx,%ds			#  seg
658200254Snyan		movw %cx,%es			#  regs
659200254Snyan		movl MEM_ESPR-0x04,%esp		# Switch to kernel stack
660200254Snyan		leal 0x44(%esp,1),%esi		# Base of frame
661200254Snyan		andb $~0x2,tss_desc+0x5		# Clear TSS busy
662200254Snyan		movb $SEL_TSS,%cl		# Set task
663200254Snyan		ltr %cx				#  register
664200254Snyan/*
665200254Snyan * Now we are back in protected mode.  The kernel stack frame set up
666200254Snyan * before entering real mode is still intact. For hardware interrupts,
667200254Snyan * leave the frame unchanged.
668200254Snyan */
669200254Snyan		cmpl $0,MEM_ESPR-0x08		# Leave saved regs unchanged
670200254Snyan		jz rret_tramp.3			#  for hardware ints
671200254Snyan/*
672200254Snyan * For V86 calls, copy the registers off of the real mode stack onto
673200254Snyan * the kernel stack as we want their updated values.  Also, initialize
674200254Snyan * the segment registers on the kernel stack.
675200254Snyan *
676200254Snyan * Note that the %esp in the kernel stack after this is garbage, but popa
677200254Snyan * ignores it, so we don't have to fix it up.
678200254Snyan */
679200254Snyan		leal -0x18(%esi),%edi		# Kernel stack GP regs
680200254Snyan		pushl %esi			# Save
681200254Snyan		movl $MEM_ESPR-0x0c,%esi	# Real mode stack GP regs
682200254Snyan		movl $8,%ecx			# Copy GP regs from
683200254Snyan		rep				#  real mode stack
684200254Snyan		movsl				#  to kernel stack
685200254Snyan		movl $SEL_UDATA,%eax		# Selector for data seg regs
686200254Snyan		movl $4,%ecx			# Initialize %ds,
687200254Snyan		rep				#  %es, %fs, and
688200254Snyan		stosl				#  %gs
689200254Snyan/*
690200254Snyan * For V86 calls, copy the saved seg regs on the real mode stack back
691200254Snyan * over to the btx_v86 structure.  Also, conditionally update the
692200254Snyan * saved eflags on the kernel stack based on the flags from the user.
693200254Snyan */
694200254Snyan		movl MEM_ESPR-0x08,%ecx		# Get btx_v86 ptr
695200254Snyan		leal V86_GS(%ecx),%edi		# %edi => btx_v86 seg regs
696200254Snyan		leal MEM_ESPR-0x2c,%esi		# %esi => real mode seg regs
697200254Snyan		xchgl %ecx,%edx			# Save btx_v86 ptr
698200254Snyan		movl $4,%ecx			# Copy seg regs
699200254Snyan		rep				#  from real mode stack
700200254Snyan		movsl				#  to btx_v86
701200254Snyan		popl %esi			# Restore
702200254Snyan		movl V86_CTL(%edx),%edx		# Read V86 control flags
703200254Snyan		testl $V86F_FLAGS,%edx		# User wants flags?
704200254Snyan		jz rret_tramp.3			# No
705200254Snyan		movl MEM_ESPR-0x3c,%eax		# Read real mode flags
706200254Snyan		movw %ax,-0x08(%esi)		# Update user flags (low 16)
707200254Snyan/*
708200254Snyan * Return to the user task
709200254Snyan */
710200254Snyanrret_tramp.3:	popl %es			# Restore
711200254Snyan		popl %ds			#  seg
712200254Snyan		popl %fs			#  regs
713200254Snyan		popl %gs
714200254Snyan		popal				# Restore gp regs
715200254Snyan		addl $4,%esp			# Discard int no
716200254Snyan		iret				# Return to user mode
717200254Snyan
718200254Snyan/*
719128710Sru * System Call.
720128710Sru */
72143561Skatointx30: 	cmpl $SYS_EXEC,%eax		# Exec system call?
72243561Skato		jne intx30.1			# No
72343561Skato		pushl %ss			# Set up
72443561Skato		popl %es			#  all
72543561Skato		pushl %es			#  segment
72643561Skato		popl %ds			#  registers
72743561Skato		pushl %ds			#  for the
72843561Skato		popl %fs			#  program
72943561Skato		pushl %fs			#  we're
73043561Skato		popl %gs			#  invoking
73143561Skato		movl $MEM_USR,%eax		# User base address
73243561Skato		addl 0xc(%esp,1),%eax		# Change to user
73343561Skato		leal 0x4(%eax),%esp		#  stack
73443561Skato		popl %eax			# Call
73543561Skato		call *%eax			#  program
73678650Skatointx30.1:	orb $0x1,%ss:btx_hdr+0x7	# Flag reboot
73743561Skato		jmp exit			# Exit
738128710Sru/*
739128710Sru * Dump structure [EBX] to [EDI], using format string [ESI].
740128710Sru */
74143561Skatodump.0: 	stosb				# Save char
74243561Skatodump:		lodsb				# Load char
74343561Skato		testb %al,%al			# End of string?
74443561Skato		jz dump.10			# Yes
74543561Skato		testb $0x80,%al 		# Control?
74643561Skato		jz dump.0			# No
74743561Skato		movb %al,%ch			# Save control
74843561Skato		movb $'=',%al			# Append
74943561Skato		stosb				#  '='
75043561Skato		lodsb				# Get offset
75143561Skato		pushl %esi			# Save
75243561Skato		movsbl %al,%esi 		# To
75343561Skato		addl %ebx,%esi			#  pointer
75443561Skato		testb $DMP_X16,%ch		# Dump word?
75543561Skato		jz dump.1			# No
75643561Skato		lodsw				# Get and
75743561Skato		call hex16			#  dump it
75843561Skatodump.1: 	testb $DMP_X32,%ch		# Dump long?
75943561Skato		jz dump.2			# No
76043561Skato		lodsl				# Get and
76143561Skato		call hex32			#  dump it
76243561Skatodump.2: 	testb $DMP_MEM,%ch		# Dump memory?
76343561Skato		jz dump.8			# No
76443561Skato		pushl %ds			# Save
765200254Snyan		testl $PSL_VM,0x50(%ebx)	# V86 mode?
76643561Skato		jnz dump.3			# Yes
76761064Snyan		verr 0x4(%esi)	 		# Readable selector?
76843561Skato		jnz dump.3			# No
76943561Skato		ldsl (%esi),%esi		# Load pointer
77043561Skato		jmp dump.4			# Join common code
77143561Skatodump.3: 	lodsl				# Set offset
77243561Skato		xchgl %eax,%edx 		# Save
77343561Skato		lodsl				# Get segment
77443561Skato		shll $0x4,%eax			#  * 0x10
77543561Skato		addl %edx,%eax			#  + offset
77643561Skato		xchgl %eax,%esi 		# Set pointer
77786497Snyandump.4: 	movb $2,%dl			# Num lines
77886497Snyandump.4a:	movb $0x10,%cl			# Bytes to dump
77943561Skatodump.5: 	lodsb				# Get byte and
78043561Skato		call hex8			#  dump it
78143561Skato		decb %cl			# Keep count
78286497Snyan		jz dump.6a			# If done
78343561Skato		movb $'-',%al			# Separator
78443561Skato		cmpb $0x8,%cl			# Half way?
78543561Skato		je dump.6			# Yes
78643561Skato		movb $' ',%al			# Use space
78743561Skatodump.6: 	stosb				# Save separator
78843561Skato		jmp dump.5			# Continue
78986497Snyandump.6a:	decb %dl			# Keep count
79086497Snyan		jz dump.7			# If done
79186497Snyan		movb $0xa,%al			# Line feed
79286497Snyan		stosb				# Save one
79386497Snyan		movb $7,%cl			# Leading
79486497Snyan		movb $' ',%al			#  spaces
79586497Snyandump.6b:	stosb				# Dump
79686497Snyan		decb %cl			#  spaces
79786497Snyan		jnz dump.6b
79886497Snyan		jmp dump.4a			# Next line
79943561Skatodump.7: 	popl %ds			# Restore
80043561Skatodump.8: 	popl %esi			# Restore
80143561Skato		movb $0xa,%al			# Line feed
80243561Skato		testb $DMP_EOL,%ch		# End of line?
80343561Skato		jnz dump.9			# Yes
80443561Skato		movb $' ',%al			# Use spaces
80543561Skato		stosb				# Save one
80643561Skatodump.9: 	jmp dump.0			# Continue
80743561Skatodump.10:	stosb				# Terminate string
80843561Skato		ret				# To caller
809128710Sru/*
810128710Sru * Convert EAX, AX, or AL to hex, saving the result to [EDI].
811128710Sru */
81243561Skatohex32:		pushl %eax			# Save
81343561Skato		shrl $0x10,%eax 		# Do upper
81443561Skato		call hex16			#  16
81543561Skato		popl %eax			# Restore
81643561Skatohex16:		call hex16.1			# Do upper 8
81743561Skatohex16.1:	xchgb %ah,%al			# Save/restore
81843561Skatohex8:		pushl %eax			# Save
81943561Skato		shrb $0x4,%al			# Do upper
82043561Skato		call hex8.1			#  4
82143561Skato		popl %eax			# Restore
82243561Skatohex8.1: 	andb $0xf,%al			# Get lower 4
82343561Skato		cmpb $0xa,%al			# Convert
82443561Skato		sbbb $0x69,%al			#  to hex
82543561Skato		das				#  digit
82643561Skato		orb $0x20,%al			# To lower case
82743561Skato		stosb				# Save char
82843561Skato		ret				# (Recursive)
829128710Sru/*
830128710Sru * Output zero-terminated string [ESI] to the console.
831128710Sru */
83243561Skatoputstr.0:	call putchr			# Output char
83343561Skatoputstr: 	lodsb				# Load char
83443561Skato		testb %al,%al			# End of string?
83543561Skato		jnz putstr.0			# No
83643561Skato		ret				# To caller
837125780Snyan#ifdef BTX_SERIAL
83886497Snyan		.set SIO_PRT,SIOPRT		# Base port
83986497Snyan		.set SIO_FMT,SIOFMT		# 8N1
84086497Snyan		.set SIO_DIV,(115200/SIOSPD)	# 115200 / SPD
84186497Snyan
842138189Snyan/*
843242863Snyan * int sio_init(void)
844138189Snyan */
84586497Snyansio_init:	movw $SIO_PRT+0x3,%dx		# Data format reg
84686497Snyan		movb $SIO_FMT|0x80,%al		# Set format
84786497Snyan		outb %al,(%dx)			#  and DLAB
84886497Snyan		pushl %edx			# Save
84986497Snyan		subb $0x3,%dl			# Divisor latch reg
85086497Snyan		movw $SIO_DIV,%ax		# Set
85186497Snyan		outw %ax,(%dx)			#  BPS
85286497Snyan		popl %edx			# Restore
85386497Snyan		movb $SIO_FMT,%al		# Clear
85486497Snyan		outb %al,(%dx)			#  DLAB
85586497Snyan		incl %edx			# Modem control reg
85686497Snyan		movb $0x3,%al			# Set RTS,
85786497Snyan		outb %al,(%dx)			#  DTR
85886497Snyan		incl %edx			# Line status reg
859242863Snyan		call sio_getc.1 		# Get character
86086497Snyan
861138189Snyan/*
862242863Snyan * int sio_flush(void)
863138189Snyan */
864242863Snyansio_flush:	xorl %eax,%eax			# Return value
865242863Snyan		xorl %ecx,%ecx			# Timeout
866242863Snyan		movb $0x80,%ch			#  counter
867242863Snyansio_flush.1:	call sio_ischar 		# Check for character
868242863Snyan		jz sio_flush.2			# Till none
869242863Snyan		loop sio_flush.1		#  or counter is zero
870242863Snyan		movb $1, %al			# Exhausted all tries
871242863Snyansio_flush.2:	ret				# To caller
87286497Snyan
873138189Snyan/*
874128710Sru * void sio_putc(int c)
875138189Snyan */
87686497Snyansio_putc:	movw $SIO_PRT+0x5,%dx		# Line status reg
87786497Snyan		xor %ecx,%ecx			# Timeout
87886497Snyan		movb $0x40,%ch			#  counter
87986497Snyansio_putc.1:	inb (%dx),%al			# Transmitter
88086497Snyan		testb $0x20,%al 		#  buffer empty?
88186497Snyan		loopz sio_putc.1		# No
88286497Snyan		jz sio_putc.2			# If timeout
88386497Snyan		movb 0x4(%esp,1),%al		# Get character
88486497Snyan		subb $0x5,%dl			# Transmitter hold reg
88586497Snyan		outb %al,(%dx)			# Write character
88686497Snyansio_putc.2:	ret $0x4			# To caller
88786497Snyan
888138189Snyan/*
889128710Sru * int sio_getc(void)
890138189Snyan */
89186497Snyansio_getc:	call sio_ischar 		# Character available?
89286497Snyan		jz sio_getc			# No
89386497Snyansio_getc.1:	subb $0x5,%dl			# Receiver buffer reg
89486497Snyan		inb (%dx),%al			# Read character
89586497Snyan		ret				# To caller
89686497Snyan
897138189Snyan/*
898128710Sru * int sio_ischar(void)
899138189Snyan */
90086497Snyansio_ischar:	movw $SIO_PRT+0x5,%dx		# Line status register
90186497Snyan		xorl %eax,%eax			# Zero
90286497Snyan		inb (%dx),%al			# Received data
90386497Snyan		andb $0x1,%al			#  ready?
90486497Snyan		ret				# To caller
90586497Snyan
906128710Sru/*
907128710Sru * Output character AL to the serial console.
908128710Sru */
90986497Snyanputchr: 	pusha				# Save
91086497Snyan		cmpb $10, %al			# is it a newline?
91186497Snyan		jne putchr.1			#  no?, then leave
91286497Snyan		push $13			# output a carriage
91386497Snyan		call sio_putc			#  return first
91486497Snyan		movb $10, %al			# restore %al
91586497Snyanputchr.1:	pushl %eax			# Push the character
91686497Snyan						#  onto the stack
91786497Snyan		call sio_putc			# Output the character
91886497Snyan		popa				# Restore
91986497Snyan		ret				# To caller
920125780Snyan#else
921128710Sru/*
922128710Sru * Output character AL to the console.
923128710Sru */
92443561Skatoputchr: 	pusha				# Save
92543561Skato		xorl %ecx,%ecx			# Zero for loops
92643561Skato		movb $SCR_MAT,%ah		# Mode/attribute
92743561Skato		movl $BDA_POS,%ebx		# BDA pointer
92843561Skato		movw (%ebx),%dx 		# Cursor position
92943561Skato		movl $0xa0000,%edi
93043561Skatoputchr.1:	cmpb $0xa,%al			# New line?
93143561Skato		je putchr.2			# Yes
93243561Skato		movw %dx,%cx
93343561Skato		movb %al,(%edi,%ecx,1)		# Write char
93443561Skato		addl $0x2000,%ecx
93543561Skato		movb %ah,(%edi,%ecx,1)		# Write attr
93643561Skato		addw $0x02,%dx
93743561Skato		jmp putchr.3
93843561Skatoputchr.2:	movw %dx,%ax
93943561Skato		movb $SCR_COL*2,%dl
94043561Skato		div %dl
94143561Skato		incb %al
94243561Skato		mul %dl
94343561Skato		movw %ax,%dx
94443561Skatoputchr.3:	cmpw $SCR_ROW*SCR_COL*2,%dx
94543561Skato		jb putchr.4			# No
94643561Skato		leal 2*SCR_COL(%edi),%esi	# New top line
94743561Skato		movw $(SCR_ROW-1)*SCR_COL/2,%cx # Words to move
94843561Skato		rep				# Scroll
94943561Skato		movsl				#  screen
95086497Snyan		movb $0x20,%al			# Space
95143561Skato		xorb %ah,%ah
95243561Skato		movb $SCR_COL,%cl		# Columns to clear
95343561Skato		rep				# Clear
95443561Skato		stosw				#  line
95543561Skato		movw $(SCR_ROW-1)*SCR_COL*2,%dx
95643561Skatoputchr.4:	movw %dx,(%ebx) 		# Update position
95743561Skato		popa				# Restore
95843561Skato		ret				# To caller
959125780Snyan#endif
96043561Skato
961200254Snyan		.code16
962200254Snyan/*
963200254Snyan * Real Mode Hardware interrupt jump table.
964200254Snyan */
965200254Snyanintr20: 	push $0x8			# Int 0x20: IRQ0
966200254Snyan		jmp int_hwr			# V86 int 0x8
967200254Snyan		push $0x9			# Int 0x21: IRQ1
968200254Snyan		jmp int_hwr			# V86 int 0x9
969200254Snyan		push $0xa			# Int 0x22: IRQ2
970200254Snyan		jmp int_hwr			# V86 int 0xa
971200254Snyan		push $0xb			# Int 0x23: IRQ3
972200254Snyan		jmp int_hwr			# V86 int 0xb
973200254Snyan		push $0xc			# Int 0x24: IRQ4
974200254Snyan		jmp int_hwr			# V86 int 0xc
975200254Snyan		push $0xd			# Int 0x25: IRQ5
976200254Snyan		jmp int_hwr			# V86 int 0xd
977200254Snyan		push $0xe			# Int 0x26: IRQ6
978200254Snyan		jmp int_hwr			# V86 int 0xe
979200254Snyan		push $0xf			# Int 0x27: IRQ7
980200254Snyan		jmp int_hwr			# V86 int 0xf
981200254Snyan		push $0x10			# Int 0x28: IRQ8
982200254Snyan		jmp int_hwr			# V86 int 0x10
983200254Snyan		push $0x11			# Int 0x29: IRQ9
984200254Snyan		jmp int_hwr			# V86 int 0x11
985200254Snyan		push $0x12			# Int 0x2a: IRQ10
986200254Snyan		jmp int_hwr			# V86 int 0x12
987200254Snyan		push $0x13			# Int 0x2b: IRQ11
988200254Snyan		jmp int_hwr			# V86 int 0x13
989200254Snyan		push $0x14			# Int 0x2c: IRQ12
990200254Snyan		jmp int_hwr			# V86 int 0x14
991200254Snyan		push $0x15			# Int 0x2d: IRQ13
992200254Snyan		jmp int_hwr			# V86 int 0x15
993200254Snyan		push $0x16			# Int 0x2e: IRQ14
994200254Snyan		jmp int_hwr			# V86 int 0x16
995200254Snyan		push $0x17			# Int 0x2f: IRQ15
996200254Snyan		jmp int_hwr			# V86 int 0x17
997200254Snyan/*
998200254Snyan * Reflect hardware interrupts in real mode.
999200254Snyan */
1000200254Snyanint_hwr: 	push %ax			# Save
1001200254Snyan		push %ds			# Save
1002200254Snyan		push %bp			# Save
1003200254Snyan		mov %sp,%bp			# Address stack frame
1004200254Snyan		xchg %bx,6(%bp)			# Swap BX, int no
1005200254Snyan		xor %ax,%ax			# Set %ds:%bx to
1006200254Snyan		shl $2,%bx			#  point to
1007200254Snyan		mov %ax,%ds			#  IDT entry
1008200254Snyan		mov (%bx),%ax			# Load IP
1009200254Snyan		mov 2(%bx),%bx			# Load CS
1010200254Snyan		xchg %ax,4(%bp)			# Swap saved %ax,%bx with
1011200254Snyan		xchg %bx,6(%bp)			#  CS:IP of handler
1012200254Snyan		pop %bp				# Restore
1013200254Snyan		pop %ds				# Restore
1014200254Snyan		lret				# Jump to handler
1015200254Snyan
101643561Skato		.p2align 4
1017128710Sru/*
1018128710Sru * Global descriptor table.
1019128710Sru */
102043561Skatogdt:		.word 0x0,0x0,0x0,0x0		# Null entry
102143561Skato		.word 0xffff,0x0,0x9a00,0xcf	# SEL_SCODE
102243561Skato		.word 0xffff,0x0,0x9200,0xcf	# SEL_SDATA
102343561Skato		.word 0xffff,0x0,0x9a00,0x0	# SEL_RCODE
102443561Skato		.word 0xffff,0x0,0x9200,0x0	# SEL_RDATA
102543561Skato		.word 0xffff,MEM_USR,0xfa00,0xcf# SEL_UCODE
102643561Skato		.word 0xffff,MEM_USR,0xf200,0xcf# SEL_UDATA
1027200254Snyantss_desc:	.word _TSSLM,MEM_TSS,0x8900,0x0 # SEL_TSS
102843561Skatogdt.1:
1029128710Sru/*
1030128710Sru * Pseudo-descriptors.
1031128710Sru */
103243561Skatogdtdesc:	.word gdt.1-gdt-1,gdt,0x0	# GDT
103343561Skatoidtdesc:	.word _IDTLM,MEM_IDT,0x0	# IDT
103443561Skatoivtdesc:	.word 0x400-0x0-1,0x0,0x0	# IVT
1035128710Sru/*
1036128710Sru * IDT construction control string.
1037128710Sru */
103843561Skatoidtctl: 	.byte 0x10,  0x8e		# Int 0x0-0xf
103943561Skato		.word 0x7dfb,intx00		#  (exceptions)
104043561Skato		.byte 0x10,  0x8e		# Int 0x10
104143561Skato		.word 0x1,   intx10		#  (exception)
104243561Skato		.byte 0x10,  0x8e		# Int 0x20-0x2f
104343561Skato		.word 0xffff,intx20		#  (hardware)
104443561Skato		.byte 0x1,   0xee		# int 0x30
104543561Skato		.word 0x1,   intx30		#  (system call)
104643561Skato		.byte 0x2,   0xee		# Int 0x31-0x32
104743561Skato		.word 0x1,   intx31		#  (V86, null)
104843561Skato		.byte 0x0			# End of string
1049128710Sru/*
1050128710Sru * Dump format string.
1051128710Sru */
105243561Skatodmpfmt: 	.byte '\n'			# "\n"
105343561Skato		.ascii "int"			# "int="
105443561Skato		.byte 0x80|DMP_X32,	   0x40 # "00000000  "
105543561Skato		.ascii "err"			# "err="
105643561Skato		.byte 0x80|DMP_X32,	   0x44 # "00000000  "
105743561Skato		.ascii "efl"			# "efl="
105843561Skato		.byte 0x80|DMP_X32,	   0x50 # "00000000  "
105943561Skato		.ascii "eip"			# "eip="
106043561Skato		.byte 0x80|DMP_X32|DMP_EOL,0x48 # "00000000\n"
106143561Skato		.ascii "eax"			# "eax="
106243561Skato		.byte 0x80|DMP_X32,	   0x34 # "00000000  "
106343561Skato		.ascii "ebx"			# "ebx="
106443561Skato		.byte 0x80|DMP_X32,	   0x28 # "00000000  "
106543561Skato		.ascii "ecx"			# "ecx="
106643561Skato		.byte 0x80|DMP_X32,	   0x30 # "00000000  "
106743561Skato		.ascii "edx"			# "edx="
106843561Skato		.byte 0x80|DMP_X32|DMP_EOL,0x2c # "00000000\n"
106943561Skato		.ascii "esi"			# "esi="
107043561Skato		.byte 0x80|DMP_X32,	   0x1c # "00000000  "
107143561Skato		.ascii "edi"			# "edi="
107243561Skato		.byte 0x80|DMP_X32,	   0x18 # "00000000  "
107343561Skato		.ascii "ebp"			# "ebp="
107443561Skato		.byte 0x80|DMP_X32,	   0x20 # "00000000  "
107543561Skato		.ascii "esp"			# "esp="
107643561Skato		.byte 0x80|DMP_X32|DMP_EOL,0x0	# "00000000\n"
107743561Skato		.ascii "cs"			# "cs="
107843561Skato		.byte 0x80|DMP_X16,	   0x4c # "0000  "
107943561Skato		.ascii "ds"			# "ds="
108043561Skato		.byte 0x80|DMP_X16,	   0xc	# "0000  "
108143561Skato		.ascii "es"			# "es="
108243561Skato		.byte 0x80|DMP_X16,	   0x8	# "0000  "
108343561Skato		.ascii "  "			# "  "
108443561Skato		.ascii "fs"			# "fs="
108543561Skato		.byte 0x80|DMP_X16,	   0x10 # "0000  "
108643561Skato		.ascii "gs"			# "gs="
108743561Skato		.byte 0x80|DMP_X16,	   0x14 # "0000  "
108843561Skato		.ascii "ss"			# "ss="
108943561Skato		.byte 0x80|DMP_X16|DMP_EOL,0x4	# "0000\n"
109043561Skato		.ascii "cs:eip" 		# "cs:eip="
109143561Skato		.byte 0x80|DMP_MEM|DMP_EOL,0x48 # "00 00 ... 00 00\n"
109243561Skato		.ascii "ss:esp" 		# "ss:esp="
109343561Skato		.byte 0x80|DMP_MEM|DMP_EOL,0x0	# "00 00 ... 00 00\n"
109486497Snyan		.asciz "BTX halted\n"		# End
1095128710Sru/*
1096200254Snyan * Bad VM86 call panic
1097200254Snyan */
1098200254Snyanbadvm86:	.asciz "Invalid VM86 Request\n"
1099200254Snyan
1100200254Snyan/*
1101128710Sru * End of BTX memory.
1102128710Sru */
110343561Skato		.p2align 4
110443561Skatobreak:
1105