wok rev 11674

add runcom
author Pascal Bellard <pascal.bellard@slitaz.org>
date Sat Feb 18 09:00:05 2012 +0100 (2012-02-18)
parents 8eec3c4a2a20
children 4da8cad96f76
files runcom/description.txt runcom/receipt runcom/stuff/Makefile runcom/stuff/debug.S runcom/stuff/debug.com runcom/stuff/debug8086.S runcom/stuff/runcom.c
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/runcom/description.txt	Sat Feb 18 09:00:05 2012 +0100
     1.3 @@ -0,0 +1,41 @@
     1.4 +Runcom support DOS .com binary files and boot sector files.
     1.5 +
     1.6 +1- The DOS .com support
     1.7 +
     1.8 +Runcom provides few BIOS and DOS (int 21H) interrupt handlers. Many .com files
     1.9 +may not work. DOS .exe are also supported.
    1.10 +You can test it with the file /usr/bin/debug.com, with the command line :
    1.11 +$ debug.com
    1.12 +
    1.13 +2- The boot sector image support
    1.14 +
    1.15 +A boot sector image is a 512 bytes file ending with the 0xAA and 0x55 bytes 
    1.16 +with the .bin extension.
    1.17 +Bios disk (int 13H) are amulated (CHS or LBA) with image file :
    1.18 +- hard disk are image ./hd0, ./hd1, ... for disk 0x80, 0x81...
    1.19 +- floppy disk are image ./fd0, ./fd1 ... or /dev/fd0, /dev/fd1 if not found.
    1.20 +You can test it with the file /usr/bin/debug.bin, with the command line :
    1.21 +$ debug.bin
    1.22 +
    1.23 +3- The boot sector debugger /usr/bin/debug.bin
    1.24 +
    1.25 +Usage:
    1.26 +
    1.27 + f DX:CX		load one CHS sector to 0000:7C00
    1.28 + t			trace one step
    1.29 + g <address>		go to adrs
    1.30 + d <address>		display 16 bytes, CR for next 16 bytes...
    1.31 + e <address> <words>...	enter memory byte/word/dword
    1.32 + m <segment>		self move
    1.33 + + <segment>		default segment offset
    1.34 +
    1.35 +seqment and offset are hexadecimal values in 0..FFFF range
    1.36 +address is linear hexadecimal value in 0..FFFFF range or seqment:offset
    1.37 +words are bytes in 00..FF range or words in 0000..FFFF range or double words
    1.38 +CX and DX are used by INT13H/AL=01 BIOS interrupt.
    1.39 +
    1.40 +Example:
    1.41 + m 0FC0			move debugger to 0FC0:0000 0FC0:01FF
    1.42 + f 1			read floppy boot sector to 0000:7C00
    1.43 + f 80 1			read hard disk master boot sector to 0000:7C00
    1.44 + g 7C0E			...
     2.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     2.2 +++ b/runcom/receipt	Sat Feb 18 09:00:05 2012 +0100
     2.3 @@ -0,0 +1,58 @@
     2.4 +# SliTaz package receipt.
     2.5 +
     2.6 +PACKAGE="runcom"
     2.7 +VERSION="1.0"
     2.8 +CATEGORY="system-tools"
     2.9 +SHORT_DESC="DOS .com binary format support"
    2.10 +MAINTAINER="dev@slitaz.org"
    2.11 +WEB_SITE="http://bellard.org/jslinux"
    2.12 +
    2.13 +# Rules to configure and make the package.
    2.14 +compile_rules()
    2.15 +{
    2.16 +	mkdir -p $src
    2.17 +	cd $src
    2.18 +	#tarball=$(wget -O - $WEB_SITE/tech.html | \
    2.19 +	#	  sed '/linuxstart/!d;s/.*href="\([^"]*\)".*/\1/')
    2.20 +	#wget $WEB_SITE/$tarball
    2.21 +	#tar xzf $tarball
    2.22 +	mkdir -p $DESTDIR/usr/bin
    2.23 +	cc -o $DESTDIR/usr/bin/runcom $stuff/runcom.c
    2.24 +	cc -o $src/debug.o -Wa,-a=$src/debug.lst -c $stuff/debug.S
    2.25 +	objcopy -O binary $src/debug.o $DESTDIR/usr/bin/debug.bin
    2.26 +	cp $stuff/debug.com $DESTDIR/usr/bin
    2.27 +	chmod +x $DESTDIR/usr/bin/debug.*
    2.28 +}
    2.29 +
    2.30 +# Rules to gen a SliTaz package suitable for Tazpkg.
    2.31 +genpkg_rules()
    2.32 +{
    2.33 +	cp -a $_pkg/* $fs
    2.34 +}
    2.35 +
    2.36 +# Post install command for Tazpkg.
    2.37 +post_install()
    2.38 +{
    2.39 +	fmt="binfmt_misc"
    2.40 +	proc="/proc/sys/fs/binfmt_misc"
    2.41 +	bin=":BOOTBIN:E::bin::/usr/bin/runcom:"
    2.42 +	com=":DOSCOM:E::com::/usr/bin/runcom:"
    2.43 +	rc="$1/etc/init.d/local.sh"
    2.44 +	grep -q "$com" $rc || cat >> $rc <<EOT
    2.45 +[ ! -e $proc/register ] && modprobe $fmt && mount -t $fmt $fmt $proc
    2.46 +echo "$bin" >$proc/register
    2.47 +echo "$com" >$proc/register
    2.48 +EOT
    2.49 +	[ -n "$1" ] && return
    2.50 +	[ ! -e $proc/register ] && modprobe $fmt && mount -t $fmt $fmt $proc
    2.51 +	echo "$bin" >$proc/register
    2.52 +	echo "$com" >$proc/register
    2.53 +}
    2.54 +
    2.55 +# Pre remove command for Tazpkg.
    2.56 +pre_remove()
    2.57 +{
    2.58 +	echo -1 > $1/proc/sys/fs/binfmt_misc/BOOTBIN
    2.59 +	echo -1 > $1/proc/sys/fs/binfmt_misc/DOSCOM
    2.60 +	sed -i '/binfmt_misc/{NN;/DOSCOM:E::com/d}' $1/etc/init.d/local.sh
    2.61 +}
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/runcom/stuff/Makefile	Sat Feb 18 09:00:05 2012 +0100
     3.3 @@ -0,0 +1,20 @@
     3.4 +CC=gcc -m32
     3.5 +CFLAGS= -O2 -Wall -fno-builtin -fno-stack-protector #-march=i386 
     3.6 +HOST_CFLAGS=-O2 -Wall
     3.7 +# modify to set the kernel path
     3.8 +KERNEL_PATH=../linux-2.6.20
     3.9 +
    3.10 +all: debug.bin debug8086.bin dbg8086.bin new.bin dbg.bin runcom
    3.11 +
    3.12 +%.bin: %.o
    3.13 +	objcopy -O binary $< $@
    3.14 +	chmod +x $@
    3.15 +
    3.16 +%.o: %.c
    3.17 +	$(CC) $(CFLAGS) -c -o $@ $<
    3.18 +
    3.19 +%.o: %.S
    3.20 +	$(CC) -D__ASSEMBLY__ -Wa,-acghlnm=$*.lst -c -o $@ $<
    3.21 +
    3.22 +clean:
    3.23 +	rm -f *.bin runcom *.o *~ 
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/runcom/stuff/debug.S	Sat Feb 18 09:00:05 2012 +0100
     4.3 @@ -0,0 +1,493 @@
     4.4 +// Usage:
     4.5 +//
     4.6 +// f DX:CX                 load one CHS sector to 0000:7C00
     4.7 +// t                       trace one step
     4.8 +// g <address>             go to adrs
     4.9 +// d <address>             display 16 bytes, CR for next 16 bytes...
    4.10 +// e <address> <words>...  enter memory byte/word/dword
    4.11 +// m <segment>             self move
    4.12 +// + <segment>             default segment offset
    4.13 +//
    4.14 +// Example:
    4.15 +// m 0FC0                  move debugger to 0FC0:0000 0FC0:01FF
    4.16 +// f 1			   read floppy boot sector to 0000:7C00
    4.17 +// f 80 1		   read hard disk master boot sector to 0000:7C00
    4.18 +// g 7C0E		   ...
    4.19 +
    4.20 +#define REGS32		28 bytes	display FS, GS and 32 bits datas for AX..DI 
    4.21 +#define ADJESDI		16 bytes	add segment overflow support for e and d
    4.22 +#define ASCIIDUMP	20 bytes	display hexa and ascii datas
    4.23 +#define INPUTBUFFER	 3 bytes	overload init code with a 32+ bytes input buffer
    4.24 +
    4.25 +.macro pushib val
    4.26 +	.byte	0x6A, \val-_start
    4.27 +.endm
    4.28 +
    4.29 +#ifdef REGS32
    4.30 +#define SEGREGSZ	10
    4.31 +#define REGSZ	32
    4.32 +#define USER_SP		REGSZ+SEGREGSZ-28(%bp)
    4.33 +#define FIXSP		14
    4.34 +#else
    4.35 +#define SEGREGSZ	6
    4.36 +#define REGSZ	16
    4.37 +#define USER_SP		REGSZ+SEGREGSZ-14(%bp)
    4.38 +#define FIXSP		10
    4.39 +#endif
    4.40 +#define USER_FLAGS	REGSZ+SEGREGSZ+4(%bp)
    4.41 +#define USER_FLAGS_HIGH	REGSZ+SEGREGSZ+5(%bp)
    4.42 +#define USER_IP		REGSZ+SEGREGSZ(%bp)
    4.43 +#define USER_CS		REGSZ+SEGREGSZ+2(%bp)
    4.44 +#define USER_CSIP	REGSZ+SEGREGSZ(%bp)
    4.45 +
    4.46 +#ifdef INPUTBUFFER
    4.47 +//#define ABS(x)		(x-(setvectors-_start))
    4.48 +#define ABS(x)		(x-32)
    4.49 +#else
    4.50 +#define ABS(x)		(x)
    4.51 +#endif
    4.52 +.macro initcode
    4.53 +	movw	$0x0FC0, %di	# move (and jump) to 0FC0:0000
    4.54 +	subw	$_startz-_start, USER_IP
    4.55 +	movw	USER_IP, %ax
    4.56 +	shrw	$4, %ax		# _start MUST be aligned on paragraph
    4.57 +	addw	USER_CS, %ax	# normalize %cs to have _start=0
    4.58 +	movw	%ax, %ds
    4.59 +.endm
    4.60 +
    4.61 +	.text
    4.62 +	.code16
    4.63 +	.org	0
    4.64 +
    4.65 +	.globl	_start
    4.66 +_start:
    4.67 +	pushf
    4.68 +	pushw	%cs
    4.69 +	stc
    4.70 +	call	init		# the start code will be overwritten by the input buffer
    4.71 +_startz:
    4.72 +
    4.73 +#ifdef INPUTBUFFER
    4.74 +isinit:
    4.75 +	initcode
    4.76 +	addw	$FIXSP, USER_SP	# adjust SP with [FLAGS CS IP DS ES [FS GS]] size
    4.77 +	pushib	setvectors
    4.78 +	jmp	moveself
    4.79 +#endif
    4.80 +
    4.81 +setvectors:
    4.82 +	xorw	%si, %si	# set interrupt vectors in 0 segment
    4.83 +	movw	%si, %ds
    4.84 +	movb	$0x7D, %cl	# skip nmi
    4.85 +hooklp:				# interrupts: 0=div0 1=step 2=nmi 3=brk 4=ov 5=bound 6=invalid
    4.86 +	pushw	%cs
    4.87 +	pushib	ABS(dbgstart)	# set %cs:dbgstart
    4.88 +	popl	(%si)		# to interrupt vector
    4.89 +skiphook:
    4.90 +	lodsl			# %si += 4
    4.91 +	shrb	$1,%cl
    4.92 +	jnc	skiphook
    4.93 +	jnz	hooklp		# note %cx will be cleared: SP will be untouched
    4.94 +	decw	(3-7)*4(%si)	# update int3 vector
    4.95 +	jmp	dbgstartz	# registers are already pushed by startup code
    4.96 +
    4.97 +regs:
    4.98 +	.ascii	"ss"
    4.99 +	.ascii	"di"  
   4.100 +	.ascii	"si"  
   4.101 +	.ascii	"bp"  
   4.102 +	.ascii	"sp"  
   4.103 +	.ascii	"bx"  
   4.104 +	.ascii	"dx"  
   4.105 +	.ascii	"cx"  
   4.106 +	.ascii	"ax"  
   4.107 +#ifdef REGS32
   4.108 +	.ascii	"gs"
   4.109 +	.ascii	"fs"
   4.110 +#endif
   4.111 +	.ascii	"es"
   4.112 +	.ascii	"ds"  
   4.113 +	.ascii	"ip"  
   4.114 +	.ascii	"cs"  
   4.115 +# Bit   Label    Desciption
   4.116 +# ---------------------------
   4.117 +# 0      CF      Carry flag
   4.118 +# 2      PF      Parity flag
   4.119 +# 4      AF      Auxiliary carry flag
   4.120 +# 6      ZF      Zero flag
   4.121 +# 7      SF      Sign flag
   4.122 +# 8      TF      Trap flag
   4.123 +# 9      IF      Interrupt enable flag
   4.124 +# 10     DF      Direction flag
   4.125 +# 11     OF      Overflow flag
   4.126 +#ifdef REGS32
   4.127 +	.ascii	"odi|sz|a|p|c"	# flags bits
   4.128 +#else
   4.129 +	.ascii	"oditsz?a?p c="	# flags bits
   4.130 +#endif
   4.131 +# 12-13  IOPL    I/O Priviledge level
   4.132 +# 14     NT      Nested task flag
   4.133 +# 16     RF      Resume flag
   4.134 +# 17     VM      Virtual 8086 mode flag
   4.135 +# 18     AC      Alignment check flag (486+)
   4.136 +# 19     VIF     Virutal interrupt flag
   4.137 +# 20     VIP     Virtual interrupt pending flag
   4.138 +# 21     ID      ID flag
   4.139 +
   4.140 +#ifdef INPUTBUFFER
   4.141 +ismove:
   4.142 +	pushw	%ax
   4.143 +moveself:
   4.144 +	popw	%si
   4.145 +#else
   4.146 +isinit:
   4.147 +	initcode
   4.148 +ismove:
   4.149 +	xorw	%si, %si
   4.150 +#endif
   4.151 +	movw	%di, %es	# move code to %di:0
   4.152 +	pushw	%di
   4.153 +#ifdef INPUTBUFFER
   4.154 +	xorw	%di, %di	# and jmp into (%di:setvectors) with retf
   4.155 +#else
   4.156 +	movw	$setvectors, %di	# and jmp into (%di:setvectors) with retf
   4.157 +	movw	%di, %si
   4.158 +#endif
   4.159 +	movw	$_end-setvectors, %cx
   4.160 +	pushw	%di
   4.161 +	rep	movsb
   4.162 +	retf
   4.163 +
   4.164 +int3:
   4.165 +	.byte	0x68		# push $0x086A	OV UP DI NT PL ZR - NA - PO - NC
   4.166 +# interrupt entry point: the registers [FLAGS CS IP] are already pushed
   4.167 +dbgstart:
   4.168 +	.byte	0x6A, 0x08	# push $0x08	NV UP DI NT PL NZ - NA - PO - NC
   4.169 +	popf
   4.170 +init:
   4.171 +	pushw	%ds
   4.172 +	pushw	%es
   4.173 +#ifdef REGS32
   4.174 +	pushw	%fs
   4.175 +	pushw	%gs
   4.176 +	pushal		#    [FLAGS CS IP DS ES FS GS] EAX ECX EDX EBX ESP EBP ESI EDI [SS]
   4.177 +#else
   4.178 +	pushaw		#    [FLAGS CS IP DS ES] AX CX DX BX SP BP SI DI [SS]
   4.179 +#endif
   4.180 +	pushw	%ss
   4.181 +	movw	%sp, %bp
   4.182 +#ifndef INPUTBUFFER
   4.183 +	pushf
   4.184 +	addw	$FIXSP, USER_SP	# adjust SP with [FLAGS CS IP DS ES [FS GS]] size
   4.185 +	popf
   4.186 +#endif
   4.187 +	jc	isinit
   4.188 +	jnz	notint3
   4.189 +	decw	USER_IP
   4.190 +	lesw	USER_CSIP, %di
   4.191 +#define OPCODE_BRK     0xCC
   4.192 +	.byte	0xB0		# movb $IM, %al
   4.193 +break:
   4.194 +	.byte	0xCC
   4.195 +	stosb
   4.196 +notint3:
   4.197 +#ifdef INPUTBUFFER
   4.198 +	addw	$FIXSP, USER_SP	# adjust SP with [FLAGS CS IP DS ES [FS GS]] size
   4.199 +#endif
   4.200 +dbgstartz:
   4.201 +dbgregslp:
   4.202 +	pushw	%cs
   4.203 +	popw	%ds
   4.204 +	movw	$ABS(regs), %si
   4.205 +#ifdef REGS32
   4.206 +	subw	%si, %bp
   4.207 +	movw	$15, %cx
   4.208 +#else
   4.209 +	movw	$13, %cx
   4.210 +#endif
   4.211 +regslp:
   4.212 +	call	putreg		# display register name and value
   4.213 +	loop	regslp
   4.214 +#ifdef REGS32
   4.215 +	movw	(%bp,%si), %dx	# get flags
   4.216 +#else
   4.217 +	movw	USER_FLAGS, %dx
   4.218 +	pushw	%si
   4.219 +	stc			# add trailing =
   4.220 +#endif
   4.221 +	movb	$13, %cl
   4.222 +	rcrw	%cl, %dx
   4.223 +nextbit:
   4.224 +	lodsb
   4.225 +	shlw	$1, %dx
   4.226 +#ifdef REGS32
   4.227 +	jnc	skipflag
   4.228 +	cmpb	$'|', %al	# remove system flags
   4.229 +	je	skipflag
   4.230 +	call	dbgputc
   4.231 +skipflag:
   4.232 +#else
   4.233 +	call	dbgputcbit	# display active flags bits
   4.234 +#endif
   4.235 +	loop	nextbit
   4.236 +#ifdef REGS32
   4.237 +	movw	%sp, %bp
   4.238 +#else
   4.239 +	popw	%si
   4.240 +	movb	$8, %cl
   4.241 +stacklp:
   4.242 +	lodsw			# si += 2
   4.243 +	call	putr16		# display flags and the beginning of the stack
   4.244 +	loop	stacklp
   4.245 +#endif
   4.246 +	call	getline
   4.247 +	lodsb
   4.248 +	xchgw	%ax, %di
   4.249 +	call	getval
   4.250 +	.byte	0x81, 0xC3	# addw	$0, %bx
   4.251 +offset_value:
   4.252 +	.word	0
   4.253 +	movw	%bx, %es
   4.254 +	xchgw	%ax, %di
   4.255 +	subb	$'m', %al
   4.256 +	je	ismove
   4.257 +	subb	$'+'-'m', %al
   4.258 +	jne	not_offset
   4.259 +	movw	%di, ABS(offset_value)
   4.260 +not_offset:
   4.261 +	orb	$1, USER_FLAGS_HIGH	# set TF
   4.262 +	subb	$'t'-'+', %al
   4.263 +	je	done
   4.264 +	subb	$'d'-'t', %al
   4.265 +	xchgw	%ax, %cx
   4.266 +	jcxz	dump		# 'd' ?
   4.267 +	loop	noenter		# 'e' ?
   4.268 +nextval:
   4.269 +	call	getval
   4.270 +	jcxz	dbgregslp
   4.271 +	xchgb	%dl, %dh
   4.272 +mextmsb:
   4.273 +	stosb
   4.274 +	xchgw	%ax, %dx
   4.275 +	xchgb	%al, %dh
   4.276 +#ifdef ADJESDI
   4.277 +	call	adjustESDI
   4.278 +#endif
   4.279 +	decw	%cx
   4.280 +	loopne	mextmsb
   4.281 +	jmp	nextval
   4.282 +noenter:
   4.283 +	loop	not_floppy_load	# f DX:CX ?
   4.284 +	movw	%es, %dx
   4.285 +	movw	%cx, %es
   4.286 +	movw	%di, %cx
   4.287 +	movw	$0x0201, %ax
   4.288 +	movw	$0x7C00, %bx
   4.289 +	pushw	%bx
   4.290 +	int	$0x13
   4.291 +	popw	%di
   4.292 +godbgregslpifc:	
   4.293 +	jc	dbgregslp
   4.294 +dump:
   4.295 +	movw	%es, %ax
   4.296 +	call	putax
   4.297 +	movw	%di, %ax
   4.298 +	call	putax
   4.299 +	movw	$16, %cx
   4.300 +dhex:
   4.301 +	movb	%es:(%di), %ah
   4.302 +#ifdef ASCIIDUMP
   4.303 +	movb	%ah, (%si)
   4.304 +	incw	%si
   4.305 +#endif
   4.306 +#ifdef ADJESDI
   4.307 +	call	incESDI
   4.308 +#else
   4.309 +	incw	%di
   4.310 +#endif
   4.311 +#ifdef REGS32
   4.312 +	movb	$0x30, %dh	# the data has 2 digits
   4.313 +#else
   4.314 +	movb	$0x01, %dh	# the data has 2 digits
   4.315 +#endif
   4.316 +	call	putx
   4.317 +	loop	dhex
   4.318 +#ifdef ASCIIDUMP
   4.319 +	movb	$16, %cl
   4.320 +	subw	%cx, %si
   4.321 +dascii:
   4.322 +	lodsb
   4.323 +	cmpb	$0x7F, %al
   4.324 +	jnc	skipascii
   4.325 +	cmpb	$0x20, %al
   4.326 +	cmc
   4.327 +skipascii:
   4.328 +	call	dbgputcbit
   4.329 +	loop	dascii
   4.330 +#endif
   4.331 +	call	dbgputcr
   4.332 +	int	$0x16
   4.333 +	cmpb	$13, %al
   4.334 +	je	dump
   4.335 +notdump:
   4.336 +not_floppy_load:
   4.337 +	stc
   4.338 +	loop	godbgregslpifc	# g ?
   4.339 +isgo:
   4.340 +	andb	$0xfe, USER_FLAGS_HIGH	# clear TF
   4.341 +	xchgw	%ax, %cx
   4.342 +	jcxz	done
   4.343 +setbreak:
   4.344 +	movb	$OPCODE_BRK, %al
   4.345 +	xchgb	%al, %es:(%di)
   4.346 +	movb	%al, ABS(break)
   4.347 +done:
   4.348 +	popw	%ax  	# %ss
   4.349 +#ifdef REGS32
   4.350 +	popal
   4.351 +	popw	%gs
   4.352 +	popw	%fs
   4.353 +#else
   4.354 +	popaw
   4.355 +#endif
   4.356 +	popw	%es
   4.357 +	popw	%ds
   4.358 +	iret
   4.359 +
   4.360 +#ifdef ADJESDI
   4.361 +adjustESDI:
   4.362 +	decw	%di
   4.363 +incESDI:
   4.364 +	incw	%di
   4.365 +	jnz	esok
   4.366 +	pushw	%es
   4.367 +	addb	$0x10,-3(%bp)
   4.368 +	popw	%es
   4.369 +esok:
   4.370 +	ret
   4.371 +#endif
   4.372 +
   4.373 +putreg:
   4.374 +	call	dbgput2c
   4.375 +	movb	$'=', %al
   4.376 +	call	dbgputc
   4.377 +putr16:
   4.378 +#ifdef REGS32
   4.379 +	movl	-2(%bp,%si), %eax
   4.380 +	movw	$0x3FC0, %dx	# check bits 7..14
   4.381 +	shrw	%cl, %dx
   4.382 +putax:
   4.383 +	movb	$0xF0, %dh	# the data has 4 digits
   4.384 +	jnc	putx		# 16 bits register ?
   4.385 +	incw	%bp		# a 32 bits register, not 16 bits
   4.386 +	incw	%bp
   4.387 +	movb	$0xFF, %dh	# the data has 8 digits
   4.388 +	jmp	putx
   4.389 +putxlp:  
   4.390 +#else
   4.391 +#	movw	_start-ABS(regs)-2(%bp,%si), %ax
   4.392 +	.byte	0x8b, 0x42, _start-ABS(regs)-2
   4.393 +putax:
   4.394 +	movb	$0x07, %dh	# the data has 4 digits
   4.395 +putx:
   4.396 +putxlp:  
   4.397 +	rolw	$4, %ax
   4.398 +#endif
   4.399 +	pushw	%ax
   4.400 +	andb	$0xf, %al
   4.401 +	addb	$0x90, %al
   4.402 +	daa
   4.403 +	adcb	$0x40, %al
   4.404 +	daa
   4.405 +	call	dbgputc
   4.406 +	popw	%ax
   4.407 +#ifdef REGS32
   4.408 +putx:
   4.409 +	roll	$4, %eax
   4.410 +#endif
   4.411 +	shrb	$1, %dh
   4.412 +	jc	putxlp
   4.413 +#ifdef REGS32
   4.414 +	jnz	putx
   4.415 +#endif
   4.416 +dbgputcbit:
   4.417 +	jc	dbgputc  
   4.418 +	mov	$0x20, %al
   4.419 +dbgputc:
   4.420 +	movw	$7, %bx
   4.421 +	mov	$0xE, %ah
   4.422 +	int	$0x10
   4.423 +	xchgw	%ax, %bx
   4.424 +#	clc				# for putax
   4.425 +	ret
   4.426 +
   4.427 +# get value in DX:AX, BX is segment CX is digits count.
   4.428 +getval:
   4.429 +	xorw	%ax, %ax
   4.430 +	xorw	%bx, %bx
   4.431 +	xorw	%cx, %cx
   4.432 +getvalz:
   4.433 +	xchgw	%ax, %bx
   4.434 +	cwd
   4.435 +	decw	%cx
   4.436 +isx:
   4.437 +	shll	$4, %edx
   4.438 +	orb	%al, %dl
   4.439 +	incw	%cx
   4.440 +gotspc:
   4.441 +getvallp:
   4.442 +	lodsb
   4.443 +	cmpb	$0x20, %al		# heat heading spaces
   4.444 +	jne	notspc
   4.445 +	jcxz	gotspc
   4.446 +notspc:
   4.447 +	subb	$'0', %al
   4.448 +	cmpb	$10, %al		# in 0..9 ?
   4.449 +	jb	isx
   4.450 +	subb	$'a'-'0'-10, %al
   4.451 +	cmpb	$16, %al		# in a..f ?
   4.452 +	jb	isx
   4.453 +	cmpb	$':'-'a'+10, %al
   4.454 +	pushl	%edx
   4.455 +	popw	%ax
   4.456 +	popw	%dx
   4.457 +	je	getvalz			# store segment in %bx
   4.458 +	pushw	%dx
   4.459 +	shlw	$12, %dx
   4.460 +	orw	%dx, %bx
   4.461 +	popw	%dx
   4.462 +	ret
   4.463 +
   4.464 +getline:
   4.465 +	call	dbgputcr
   4.466 +getlinebs:
   4.467 +	cmpw	$ABS(buffer), %si
   4.468 +	je	getc
   4.469 +	decw	%si
   4.470 +getlinelp:
   4.471 +	call	dbgputc
   4.472 +getc:
   4.473 +	int	$0x16
   4.474 +	cmpb	$8, %al
   4.475 +	je	getlinebs
   4.476 +	orb	$0x20, %al
   4.477 +	movb	%al, (%si)
   4.478 +	inc	%si
   4.479 +	cmpb	$0x2D, %al
   4.480 +	jne	getlinelp
   4.481 +dbgputcr:
   4.482 +	movw	$ABS(crlf), %si
   4.483 +dbgput2c:
   4.484 +	call	dbgput1c
   4.485 +dbgput1c:
   4.486 +	lodsb
   4.487 +	jmp	dbgputc
   4.488 +
   4.489 +crlf:
   4.490 +	.byte	13,10
   4.491 +_end:
   4.492 +buffer:
   4.493 +
   4.494 +	.org	510
   4.495 +	.byte	0x55, 0xAA
   4.496 +
     5.1 Binary file runcom/stuff/debug.com has changed
     6.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     6.2 +++ b/runcom/stuff/debug8086.S	Sat Feb 18 09:00:05 2012 +0100
     6.3 @@ -0,0 +1,477 @@
     6.4 +// Usage:
     6.5 +//
     6.6 +// f DX:CX                 load one CHS sector to 0000:7C00
     6.7 +// t                       trace one step
     6.8 +// g <address>             go to adrs
     6.9 +// d <address>             display 16 bytes, CR for next 16 bytes...
    6.10 +// e <address> <words>...  enter memory byte/word/dword
    6.11 +// m <segment>             self move
    6.12 +// + <segment>             default segment offset
    6.13 +//
    6.14 +// Example:
    6.15 +// m 0FC0                  move debugger to 0FC0:0000 0FC0:01FF
    6.16 +// f 1			   read floppy boot sector to 0000:7C00
    6.17 +// f 80 1		   read hard disk master boot sector to 0000:7C00
    6.18 +// g 7C0E		   ...
    6.19 +
    6.20 +#define ADJESDI		16 bytes	add segment overflow support for e and d
    6.21 +#define ASCIIDUMP	20 bytes	display hexa and ascii datas
    6.22 +#define INPUTBUFFER	 2 bytes	overload init code with a 32+ bytes input buffer
    6.23 +//#define CPU186       -26 bytes	80186+ CPU
    6.24 +
    6.25 +.macro pusham
    6.26 +	pushw	%ax
    6.27 +	pushw	%cx
    6.28 +	pushw	%dx
    6.29 +	pushw	%bx
    6.30 +	movw	%sp, %bx
    6.31 +	leaw	14(%bx), %bx	# adjust SP with [FLAGS CS IP AX CX DX BX] size
    6.32 +	pushw	%bx	# %sp
    6.33 +	pushw	%bp
    6.34 +	pushw	%si
    6.35 +	pushw	%di
    6.36 +.endm
    6.37 +
    6.38 +.macro popam
    6.39 +	popw	%di
    6.40 +	popw	%si
    6.41 +	popw	%bp
    6.42 +	popw	%ax	# %sp
    6.43 +	popw	%bx
    6.44 +	popw	%dx
    6.45 +	popw	%cx
    6.46 +	popw	%ax
    6.47 +.endm
    6.48 +
    6.49 +#ifdef INPUTBUFFER
    6.50 +//#define ABS(x)		(x-(setvectors-_start))
    6.51 +#define ABS(x)		(x-30)
    6.52 +#else
    6.53 +#define ABS(x)		(x)
    6.54 +#endif
    6.55 +
    6.56 +#define SEGREGSZ	6
    6.57 +#define REGSZ	16
    6.58 +#define USER_SP		REGSZ+SEGREGSZ-10(%bp)
    6.59 +#define USER_FLAGS	REGSZ+SEGREGSZ+4(%bp)
    6.60 +#define USER_FLAGS_HIGH	REGSZ+SEGREGSZ+5(%bp)
    6.61 +#define USER_IP		REGSZ+SEGREGSZ(%bp)
    6.62 +#define USER_CS		REGSZ+SEGREGSZ+2(%bp)
    6.63 +#define USER_CSIP	REGSZ+SEGREGSZ(%bp)
    6.64 +
    6.65 +.macro initcode
    6.66 +	movw	$0x0FC0, %di	# move (and jump) to 0FC0:0000
    6.67 +	subw	$_startz-_start, USER_IP
    6.68 +	movw	USER_IP, %ax
    6.69 +#ifdef CPU186
    6.70 +	cld			# ensure movsb will work
    6.71 +	shrw	$4, %ax		# _start MUST be aligned on paragraph
    6.72 +#else
    6.73 +	movb	$4, %cl
    6.74 +	shrw	%cl, %ax	# _start MUST be aligned on paragraph
    6.75 +#endif
    6.76 +	addw	USER_CS, %ax	# normalize %cs to have _start=0
    6.77 +	movw	%ax, %ds
    6.78 +.endm
    6.79 +	.text
    6.80 +	.code16
    6.81 +#ifdef CPU186
    6.82 +	.arch	i186
    6.83 +#else
    6.84 +	.arch	i8086
    6.85 +#endif
    6.86 +	.org	0
    6.87 +
    6.88 +	.globl	_start
    6.89 +_start:
    6.90 +	pushf
    6.91 +	pushw	%cs
    6.92 +	stc
    6.93 +	call	init		# the start code will be overwritten by the input buffer
    6.94 +_startz:
    6.95 +
    6.96 +#ifdef INPUTBUFFER
    6.97 +isinit:
    6.98 +	initcode
    6.99 +	movw	$setvectors, %si
   6.100 +	jmp	moveself
   6.101 +#endif
   6.102 +
   6.103 +setvectors:
   6.104 +	xorw	%si, %si	# set interrupt vectors in 0 segment
   6.105 +	movw	%si, %ds
   6.106 +	movb	$0xF9, %ch	# skip nmi
   6.107 +hooklp:				# interrupts: 0=div0 1=step 2=nmi 3=brk 4=ov 5=bound 6=invalid
   6.108 +	movw	$ABS(dbgstart), (%si)	# set %cs:dbgstart
   6.109 +	lodsw			# %si += 2
   6.110 +	movw	%cs, (%si)	# to interrupt vector
   6.111 +skiphook:
   6.112 +	lodsw			# %si += 2
   6.113 +	shrb	$1,%ch
   6.114 +	jnc	skiphook
   6.115 +	jnz	hooklp		# note %cx will be cleared: SP will be untouched
   6.116 +#ifdef CPU186
   6.117 +	decw	(3-7)*4(%si)	# update int3 vector
   6.118 +#else
   6.119 +	movb	$ABS(int3), (3-7)*4(%si)	# update int3 vector
   6.120 +#endif
   6.121 +	jmp	dbgstartz	# registers are already pushed by startup code
   6.122 +
   6.123 +regs:
   6.124 +	.ascii	"ss"
   6.125 +	.ascii	"es"
   6.126 +	.ascii	"ds"  
   6.127 +	.ascii	"di"  
   6.128 +	.ascii	"si"  
   6.129 +	.ascii	"bp"  
   6.130 +	.ascii	"sp"  
   6.131 +	.ascii	"bx"  
   6.132 +	.ascii	"dx"  
   6.133 +	.ascii	"cx"  
   6.134 +	.ascii	"ax"  
   6.135 +	.ascii	"ip"  
   6.136 +	.ascii	"cs"  
   6.137 +# Bit   Label    Desciption
   6.138 +# ---------------------------
   6.139 +# 0      CF      Carry flag
   6.140 +# 2      PF      Parity flag
   6.141 +# 4      AF      Auxiliary carry flag
   6.142 +# 6      ZF      Zero flag
   6.143 +# 7      SF      Sign flag
   6.144 +# 8      TF      Trap flag
   6.145 +# 9      IF      Interrupt enable flag
   6.146 +# 10     DF      Direction flag
   6.147 +# 11     OF      Overflow flag
   6.148 +	.ascii	"oditsz?a?p c="	# flags bits
   6.149 +
   6.150 +int3:
   6.151 +#ifdef CPU186
   6.152 +	.byte	0x68		# push $0x086A	OV UP DI NT PL ZR - NA - PO - NC
   6.153 +# interrupt entry point: the registers [FLAGS CS IP] are already pushed
   6.154 +dbgstart:
   6.155 +	.byte	0x6A, 0x08	# push $0x08	NV UP DI NT PL NZ - NA - PO - NC
   6.156 +	popf
   6.157 +init:
   6.158 +	pushaw		#    [FLAGS CS IP] AX CX DX BX SP BP SI DI [DS ES SS]
   6.159 +#else
   6.160 +	stc
   6.161 +	.byte	0x73		# jnc
   6.162 +# interrupt entry point: the registers [FLAGS CS IP] are already pushed
   6.163 +dbgstart:
   6.164 +	clc
   6.165 +	pushw	%ax
   6.166 +	sbbw	%ax,%ax		# copy CF to SF
   6.167 +	clc
   6.168 +	popw	%ax
   6.169 +init:
   6.170 +	cld			# ensure movsb will work
   6.171 +	pusham		#    [FLAGS CS IP] AX CX DX BX SP BP SI DI [DS ES SS]
   6.172 +#endif
   6.173 +	pushw	%ds
   6.174 +	pushw	%es
   6.175 +	pushw	%ss
   6.176 +	movw	%sp, %bp
   6.177 +#ifdef CPU186
   6.178 +	pushf
   6.179 +	addw	$6, USER_SP	# adjust SP with [FLAGS CS IP] size
   6.180 +	popf
   6.181 +#endif
   6.182 +	jc	isinit
   6.183 +	jns	notint3
   6.184 +	decw	USER_IP
   6.185 +	lesw	USER_CSIP, %di
   6.186 +#define OPCODE_BRK     0xCC
   6.187 +	.byte	0xB0		# movb $IM, %al
   6.188 +break:
   6.189 +	.byte	0xCC
   6.190 +	stosb
   6.191 +notint3:
   6.192 +dbgstartz:
   6.193 +dbgregslp:
   6.194 +	call	getcmd
   6.195 +	.byte	0x81, 0xC3	# addw	$0, %bx
   6.196 +offset_value:
   6.197 +	.word	0
   6.198 +	movw	%bx, %es
   6.199 +	xchgw	%ax, %di
   6.200 +	subb	$'m', %al
   6.201 +	jne	isinotmove
   6.202 +#ifdef INPUTBUFFER
   6.203 +ismove:
   6.204 +	xchgw	%ax, %si
   6.205 +moveself:
   6.206 +#else
   6.207 +isinit:
   6.208 +	jmp	ismove
   6.209 +	initcode
   6.210 +ismove:
   6.211 +#endif
   6.212 +	movw	%di, %es	# move code to %di:0
   6.213 +	pushw	%di
   6.214 +#ifdef INPUTBUFFER
   6.215 +	xorw	%di, %di	# and jmp into (%di:setvectors) with retf
   6.216 +#else
   6.217 +	movw	$setvectors, %di	# and jmp into (%di:setvectors) with retf
   6.218 +	movw	%di, %si
   6.219 +#endif
   6.220 +	movw	$_end-setvectors, %cx
   6.221 +	pushw	%di
   6.222 +	rep	movsb
   6.223 +	retf
   6.224 +
   6.225 +isinotmove:
   6.226 +	subb	$'+'-'m', %al
   6.227 +	jne	not_offset
   6.228 +	movw	%di, ABS(offset_value)
   6.229 +not_offset:
   6.230 +	orb	$1, USER_FLAGS_HIGH	# set TF
   6.231 +	subb	$'t'-'+', %al
   6.232 +	je	done
   6.233 +	subb	$'d'-'t', %al
   6.234 +	xchgw	%ax, %cx
   6.235 +	jcxz	dump		# 'd' ?
   6.236 +	loop	noenter		# 'e' ?
   6.237 +nextval:
   6.238 +	call	getval
   6.239 +	jcxz	dbgregslp
   6.240 +	xchgb	%dl, %dh
   6.241 +mextmsb:
   6.242 +	stosb
   6.243 +	xchgw	%ax, %dx
   6.244 +	xchgb	%al, %dh
   6.245 +#ifdef ADJESDI
   6.246 +	call	adjustESDI
   6.247 +#endif
   6.248 +	decw	%cx
   6.249 +	loopne	mextmsb
   6.250 +	jmp	nextval
   6.251 +noenter:
   6.252 +	loop	not_floppy_load	# f DX:CX ?
   6.253 +	movw	%es, %dx
   6.254 +	movw	%cx, %es
   6.255 +	movw	%di, %cx
   6.256 +	movw	$0x0201, %ax
   6.257 +	movw	$0x7C00, %bx
   6.258 +	pushw	%bx
   6.259 +	int	$0x13
   6.260 +	popw	%di
   6.261 +godbgregslpifc:	
   6.262 +	jc	dbgregslp
   6.263 +dump:
   6.264 +	movw	%es, %ax
   6.265 +	call	putax
   6.266 +	movw	%di, %ax
   6.267 +	call	putax
   6.268 +	movw	$16, %cx
   6.269 +dhex:
   6.270 +	movb	%es:(%di), %ah
   6.271 +#ifdef ASCIIDUMP
   6.272 +	movb	%ah, (%si)
   6.273 +	incw	%si
   6.274 +#endif
   6.275 +#ifdef ADJESDI
   6.276 +	call	incESDI
   6.277 +#else
   6.278 +	incw	%di
   6.279 +#endif
   6.280 +	movb	$0x01, %dh	# the data has 2 digits
   6.281 +	call	putx
   6.282 +	loop	dhex
   6.283 +#ifdef ASCIIDUMP
   6.284 +	movb	$16, %cl
   6.285 +	subw	%cx, %si
   6.286 +dascii:
   6.287 +	lodsb
   6.288 +	cmpb	$0x7F, %al
   6.289 +	jnc	skipascii
   6.290 +	cmpb	$0x20, %al
   6.291 +	cmc
   6.292 +skipascii:
   6.293 +	call	dbgputcbit
   6.294 +	loop	dascii
   6.295 +#endif
   6.296 +	call	dbgputcr
   6.297 +	int	$0x16
   6.298 +	cmpb	$13, %al
   6.299 +	je	dump
   6.300 +notdump:
   6.301 +not_floppy_load:
   6.302 +	stc
   6.303 +	loop	godbgregslpifc	# g ?
   6.304 +isgo:
   6.305 +	andb	$0xfe, USER_FLAGS_HIGH	# clear TF
   6.306 +	xchgw	%ax, %cx
   6.307 +	jcxz	done
   6.308 +setbreak:
   6.309 +	movb	$OPCODE_BRK, %al
   6.310 +	xchgb	%al, %es:(%di)
   6.311 +	movb	%al, ABS(break)
   6.312 +done:
   6.313 +	popw	%ax  	# %ss
   6.314 +	popw	%es
   6.315 +	popw	%ds
   6.316 +#ifdef CPU186
   6.317 +	popaw
   6.318 +#else
   6.319 +	popam
   6.320 +#endif
   6.321 +	iret
   6.322 +
   6.323 +#ifdef ADJESDI
   6.324 +adjustESDI:
   6.325 +	decw	%di
   6.326 +incESDI:
   6.327 +	incw	%di
   6.328 +	jnz	esok
   6.329 +	pushw	%es
   6.330 +	addb	$0x10,-3(%bp)
   6.331 +	popw	%es
   6.332 +esok:
   6.333 +	ret
   6.334 +#endif
   6.335 +
   6.336 +putreg:
   6.337 +	call	dbgput2c
   6.338 +	movb	$'=', %al
   6.339 +	call	dbgputc
   6.340 +putr16:
   6.341 +#	movw	_start-ABS(regs)-2(%bp,%si), %ax
   6.342 +	.byte	0x8b, 0x42, _start-ABS(regs)-2
   6.343 +putax:
   6.344 +	movb	$0x07, %dh	# the data has 4 digits
   6.345 +putx:
   6.346 +putxlp:  
   6.347 +#ifdef CPU186
   6.348 +	rolw	$4, %ax
   6.349 +#else
   6.350 +	pushw	%cx
   6.351 +	movb	$4, %cl
   6.352 +	rolw	%cl, %ax
   6.353 +	popw	%cx
   6.354 +#endif
   6.355 +	pushw	%ax
   6.356 +	andb	$0xf, %al
   6.357 +	addb	$0x90, %al
   6.358 +	daa
   6.359 +	adcb	$0x40, %al
   6.360 +	daa
   6.361 +	call	dbgputc
   6.362 +	popw	%ax
   6.363 +	shrb	$1, %dh
   6.364 +	jc	putxlp
   6.365 +dbgputcbit:
   6.366 +	jc	dbgputc  
   6.367 +	mov	$0x20, %al
   6.368 +dbgputc:
   6.369 +	movw	$7, %bx
   6.370 +	mov	$0xE, %ah
   6.371 +	int	$0x10
   6.372 +	xchgw	%ax, %bx
   6.373 +	ret
   6.374 +
   6.375 +getline:
   6.376 +	movw	$ABS(regs), %si
   6.377 +	movw	$13, %cx
   6.378 +regslp:
   6.379 +	call	putreg		# display register name and value
   6.380 +	loop	regslp
   6.381 +	movw	USER_FLAGS, %dx
   6.382 +	pushw	%si
   6.383 +	movb	$13, %cl
   6.384 +	stc			# add trailing =
   6.385 +	rcrw	%cl, %dx
   6.386 +nextbit:
   6.387 +	lodsb
   6.388 +	shlw	$1, %dx
   6.389 +	call	dbgputcbit	# display active flags bits
   6.390 +	loop	nextbit
   6.391 +	popw	%si
   6.392 +	movb	$8, %cl
   6.393 +stacklp:
   6.394 +	lodsw			# si += 2
   6.395 +	call	putr16		# display flags and the beginning of the stack
   6.396 +	loop	stacklp
   6.397 +	call	dbgputcr
   6.398 +getlinebs:
   6.399 +	cmpw	$ABS(buffer), %si
   6.400 +	je	getc
   6.401 +	decw	%si
   6.402 +getlinelp:
   6.403 +	call	dbgputc
   6.404 +getc:
   6.405 +	int	$0x16
   6.406 +	cmpb	$8, %al
   6.407 +	je	getlinebs
   6.408 +	orb	$0x20, %al
   6.409 +	movb	%al, (%si)
   6.410 +	inc	%si
   6.411 +	cmpb	$0x2D, %al
   6.412 +	jne	getlinelp
   6.413 +dbgputcr:
   6.414 +	movw	$ABS(crlf), %si
   6.415 +dbgput2c:
   6.416 +	call	dbgput1c
   6.417 +dbgput1c:
   6.418 +	lodsb
   6.419 +	jmp	dbgputc
   6.420 +
   6.421 +getcmd:
   6.422 +	pushw	%cs
   6.423 +	popw	%ds
   6.424 +	call	getline
   6.425 +	lodsb
   6.426 +	xchgw	%ax, %di
   6.427 +# get value in DX:AX, BX is segment CX is digits count.
   6.428 +getval:
   6.429 +	xorw	%bx, %bx
   6.430 +	xorw	%cx, %cx
   6.431 +getvalz:
   6.432 +	pushw	%bx			# save segment
   6.433 +	xorw	%bx, %bx
   6.434 +	mul	%bx			# clear %dx:%ax
   6.435 +	decw	%cx
   6.436 +isx:
   6.437 +	incw	%cx
   6.438 +	orb	$0xE0, %dh
   6.439 +getvalbit:
   6.440 +	shlw	$1, %bx
   6.441 +	rclw	$1, %dx
   6.442 +	jc	getvalbit
   6.443 +	orb	%al, %bl
   6.444 +gotspc:
   6.445 +	lodsb
   6.446 +	cmpb	$0x20, %al		# space ?
   6.447 +	jne	notspc
   6.448 +	jcxz	gotspc
   6.449 +notspc:
   6.450 +	sub	$'0', %al
   6.451 +	cmpb	$10, %al		# in 0..9 ?
   6.452 +	jb	isx
   6.453 +	sub	$'a'-'0'-10, %al
   6.454 +	cmpb	$16, %al		# in a..f ?
   6.455 +	jb	isx
   6.456 +	cmpb	$':'-'a'+10, %al
   6.457 +	popw	%ax
   6.458 +	je	getvalz			# store segment in %bx
   6.459 +	xchgw	%ax, %bx
   6.460 +	pushw	%dx
   6.461 +#ifdef CPU186
   6.462 +	shlw	$12, %dx
   6.463 +#else
   6.464 +	pushw	%cx
   6.465 +	movb	$12, %cl
   6.466 +	shlw	%cl, %dx
   6.467 +	popw	%cx
   6.468 +#endif
   6.469 +	addw	%dx, %bx
   6.470 +	popw	%dx
   6.471 +	ret
   6.472 +
   6.473 +crlf:
   6.474 +	.byte	13,10
   6.475 +_end:
   6.476 +buffer:
   6.477 +
   6.478 +	.org	510
   6.479 +	.byte	0x55, 0xAA
   6.480 +
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/runcom/stuff/runcom.c	Sat Feb 18 09:00:05 2012 +0100
     7.3 @@ -0,0 +1,1364 @@
     7.4 +/*
     7.5 + * Simple example of use of vm86: launch a basic .com DOS executable
     7.6 + */
     7.7 +#include <stdlib.h>
     7.8 +#include <stdio.h>
     7.9 +#include <string.h>
    7.10 +#include <inttypes.h>
    7.11 +#include <unistd.h>
    7.12 +#include <fcntl.h>
    7.13 +#include <time.h>
    7.14 +#include <sys/mman.h>
    7.15 +#include <sys/ioctl.h>
    7.16 +#include <sys/time.h>
    7.17 +#include <sys/types.h>
    7.18 +#include <sys/stat.h>
    7.19 +#include <signal.h>
    7.20 +#include <errno.h>
    7.21 +#include <ctype.h>
    7.22 +#include <termios.h>
    7.23 +
    7.24 +#include <sys/syscall.h>
    7.25 +#include <asm/vm86.h>
    7.26 +
    7.27 +//#define DUMP_INT21
    7.28 +
    7.29 +static inline int vm86(int func, struct vm86plus_struct *v86)
    7.30 +{
    7.31 +    return syscall(__NR_vm86, func, v86);
    7.32 +}
    7.33 +
    7.34 +#define CF_MASK 		0x00000001
    7.35 +#define ZF_MASK 		0x00000040
    7.36 +#define TF_MASK 		0x00000100
    7.37 +#define IF_MASK 		0x00000200
    7.38 +#define DF_MASK 		0x00000400
    7.39 +#define IOPL_MASK		0x00003000
    7.40 +#define NT_MASK	         	0x00004000
    7.41 +#define RF_MASK			0x00010000
    7.42 +#define VM_MASK			0x00020000
    7.43 +#define AC_MASK			0x00040000
    7.44 +#define VIF_MASK                0x00080000
    7.45 +#define VIP_MASK                0x00100000
    7.46 +#define ID_MASK                 0x00200000
    7.47 +
    7.48 +void usage(void)
    7.49 +{
    7.50 +    printf("runcom version 0.2-slitaz (c) 2003-2011 Fabrice Bellard\n"
    7.51 +           "usage: runcom file.com [args...]\n"
    7.52 +           "Run simple .com DOS executables (linux vm86 test mode)\n");
    7.53 +    exit(1);
    7.54 +}
    7.55 +
    7.56 +static inline void set_bit(uint8_t *a, unsigned int bit)
    7.57 +{
    7.58 +    a[bit / 8] |= (1 << (bit % 8));
    7.59 +}
    7.60 +
    7.61 +static inline uint8_t *seg_to_linear(unsigned int seg, unsigned int reg)
    7.62 +{
    7.63 +    return (uint8_t *)((seg << 4) + (reg & 0xffff));
    7.64 +}
    7.65 +
    7.66 +static inline void pushw(struct vm86_regs *r, int val)
    7.67 +{
    7.68 +    r->esp = (r->esp & ~0xffff) | ((r->esp - 2) & 0xffff);
    7.69 +    *(uint16_t *)seg_to_linear(r->ss, r->esp) = val;
    7.70 +}
    7.71 +
    7.72 +void dump_regs(struct vm86_regs *r)
    7.73 +{
    7.74 +    int i;
    7.75 +    uint8_t *p8;
    7.76 +    uint16_t *p16;
    7.77 +    fprintf(stderr,
    7.78 +            "EAX=%08lx EBX=%08lx ECX=%08lx EDX=%08lx\n"
    7.79 +            "ESI=%08lx EDI=%08lx EBP=%08lx ESP=%08lx\n"
    7.80 +            "EIP=%08lx EFL=%08lx "
    7.81 +            "CS=%04x DS=%04x ES=%04x SS=%04x FS=%04x GS=%04x\n[SP]",
    7.82 +            r->eax, r->ebx, r->ecx, r->edx, r->esi, r->edi, r->ebp, r->esp,
    7.83 +            r->eip, r->eflags,
    7.84 +            r->cs, r->ds, r->es, r->ss, r->fs, r->gs);
    7.85 +    for (p16 = (uint16_t *) seg_to_linear(r->ss, r->esp), i = 0; i < 15; i++)
    7.86 +    	fprintf(stderr," %04x", *p16++);
    7.87 +    fprintf(stderr,"\n[IP]");
    7.88 +    for (p8 = seg_to_linear(r->cs, r->eip), i = 0; i < 25; i++)
    7.89 +    	fprintf(stderr," %02x", *p8++);
    7.90 +    fprintf(stderr,"\n");
    7.91 +}
    7.92 +
    7.93 +#define DOS_FD_MAX 256
    7.94 +typedef struct {
    7.95 +    int fd; /* -1 means closed */
    7.96 +} DOSFile;
    7.97 +
    7.98 +DOSFile dos_files[DOS_FD_MAX];
    7.99 +uint16_t cur_psp;
   7.100 +
   7.101 +void dos_init(void)
   7.102 +{
   7.103 +    int i;
   7.104 +    for(i = 0; i < DOS_FD_MAX; i++)
   7.105 +        dos_files[i].fd = (i < 3) ? i : -1;
   7.106 +}
   7.107 +
   7.108 +static inline void set_error(struct vm86_regs *r, int val)
   7.109 +{
   7.110 +    r->eflags &= ~CF_MASK;
   7.111 +    if (val) {
   7.112 +        r->eax = (r->eax & ~0xffff) | val;
   7.113 +        r->eflags |= CF_MASK;
   7.114 +    }
   7.115 +}
   7.116 +static DOSFile *get_file(int h)
   7.117 +{
   7.118 +    DOSFile *fh;
   7.119 +
   7.120 +    if (h < DOS_FD_MAX) {
   7.121 +        fh = &dos_files[h];
   7.122 +        if (fh->fd != -1)
   7.123 +            return fh;
   7.124 +    }
   7.125 +    return NULL;
   7.126 +}
   7.127 +
   7.128 +/* return -1 if error */
   7.129 +static int get_new_handle(void)
   7.130 +{
   7.131 +    DOSFile *fh;
   7.132 +    int i;
   7.133 +
   7.134 +    for(i = 0; i < DOS_FD_MAX; i++) {
   7.135 +        fh = &dos_files[i];
   7.136 +        if (fh->fd == -1)
   7.137 +            return i;
   7.138 +    }
   7.139 +    return -1;
   7.140 +}
   7.141 +
   7.142 +static char *get_filename1(struct vm86_regs *r, char *buf, int buf_size,
   7.143 +                           uint16_t seg, uint16_t offset)
   7.144 +{
   7.145 +    char *q;
   7.146 +    int c;
   7.147 +    q = buf;
   7.148 +    for(;;) {
   7.149 +        c = *seg_to_linear(seg, offset);
   7.150 +        if (c == 0)
   7.151 +            break;
   7.152 +        if (q >= buf + buf_size - 1)
   7.153 +            break;
   7.154 +        c = tolower(c);
   7.155 +        if (c == '\\')
   7.156 +            c = '/';
   7.157 +        *q++ = c;
   7.158 +        offset++;
   7.159 +    }
   7.160 +    *q = '\0';
   7.161 +    return buf;
   7.162 +} 
   7.163 +
   7.164 +static char *get_filename(struct vm86_regs *r, char *buf, int buf_size)
   7.165 +{
   7.166 +    return get_filename1(r, buf, buf_size, r->ds, r->edx & 0xffff);
   7.167 +}
   7.168 +
   7.169 +typedef struct __attribute__((packed)) {
   7.170 +    uint8_t drive_num;
   7.171 +    uint8_t file_name[8];
   7.172 +    uint8_t file_ext[3];
   7.173 +    uint16_t current_block;
   7.174 +    uint16_t logical_record_size;
   7.175 +    uint32_t file_size;
   7.176 +    uint16_t date;
   7.177 +    uint16_t time;
   7.178 +    uint8_t reserved[8];
   7.179 +    uint8_t record_in_block;
   7.180 +    uint32_t record_num;
   7.181 +} FCB;
   7.182 +
   7.183 +typedef struct __attribute__((packed)) {
   7.184 +    uint16_t environ;
   7.185 +    uint16_t cmdtail_off;
   7.186 +    uint16_t cmdtail_seg;
   7.187 +    uint32_t fcb1;
   7.188 +    uint32_t fcb2;
   7.189 +    uint16_t sp, ss;
   7.190 +    uint16_t ip, cs;
   7.191 +} ExecParamBlock;
   7.192 +
   7.193 +typedef struct MemBlock {
   7.194 +    struct MemBlock *next;
   7.195 +    uint16_t seg;
   7.196 +    uint16_t size; /* in paragraphs */
   7.197 +} MemBlock;
   7.198 +
   7.199 +/* first allocated paragraph */
   7.200 +MemBlock *first_mem_block = NULL;
   7.201 +
   7.202 +#define MEM_START 0x1000
   7.203 +#define MEM_END   0xa000
   7.204 +
   7.205 +/* return -1 if error */
   7.206 +int mem_malloc(int size, int *pmax_size)
   7.207 +{
   7.208 +    MemBlock *m, **pm;
   7.209 +    int seg_free, seg;
   7.210 +    
   7.211 +    /* XXX: this is totally inefficient, but we have only 1 or 2
   7.212 +       blocks ! */
   7.213 +    seg_free = MEM_START;
   7.214 +    for(pm = &first_mem_block; *pm != NULL; pm = &(*pm)->next) {
   7.215 +        m = *pm;
   7.216 +        seg = m->seg + m->size;
   7.217 +        if (seg > seg_free)
   7.218 +            seg_free = seg;
   7.219 +    }
   7.220 +    if ((seg_free + size) > MEM_END)
   7.221 +        return -1;
   7.222 +    if (pmax_size)
   7.223 +        *pmax_size = MEM_END - seg_free;
   7.224 +    /* add at the end */
   7.225 +    m = malloc(sizeof(MemBlock));
   7.226 +    *pm = m;
   7.227 +    m->next = NULL;
   7.228 +    m->seg = seg_free;
   7.229 +    m->size = size;
   7.230 +#ifdef DUMP_INT21
   7.231 +    printf("mem_malloc size=0x%04x: 0x%04x\n", size, seg_free);
   7.232 +#endif
   7.233 +    return seg_free;
   7.234 +}
   7.235 +
   7.236 +/* return -1 if error */
   7.237 +int mem_free(int seg)
   7.238 +{
   7.239 +    MemBlock *m, **pm;
   7.240 +    for(pm = &first_mem_block; *pm != NULL; pm = &(*pm)->next) {
   7.241 +        m = *pm;
   7.242 +        if (m->seg == seg) {
   7.243 +            *pm = m->next;
   7.244 +            free(m);
   7.245 +            return 0;
   7.246 +        }
   7.247 +    }
   7.248 +    return -1;
   7.249 +}
   7.250 +
   7.251 +/* return -1 if error or the maxmium size */
   7.252 +int mem_resize(int seg, int new_size)
   7.253 +{
   7.254 +    MemBlock *m, **pm, *m1;
   7.255 +    int max_size;
   7.256 +
   7.257 +    for(pm = &first_mem_block; *pm != NULL; pm = &(*pm)->next) {
   7.258 +        m = *pm;
   7.259 +        if (m->seg == seg) {
   7.260 +            m1 = m->next;
   7.261 +            if (!m1)
   7.262 +                max_size = MEM_END - m->seg;
   7.263 +            else
   7.264 +                max_size = m1->seg - m->seg;
   7.265 +            if (new_size > max_size)
   7.266 +                return -1;
   7.267 +            m->size = new_size;
   7.268 +            return max_size;
   7.269 +        }
   7.270 +    }
   7.271 +    return -1;
   7.272 +}
   7.273 +
   7.274 +int load_boot(const char *filename, struct vm86_regs *r)
   7.275 +{
   7.276 +    int fd, ret;
   7.277 +
   7.278 +    /* load the boot sector */
   7.279 +    fd = open(filename, O_RDONLY);
   7.280 +    if (fd >= 0) {
   7.281 +    	*seg_to_linear(0x0, 0x7dff) = 0;
   7.282 +        r->eax = 0x200;
   7.283 +        r->ebx = r->esp = r->eip = 0x7c00;
   7.284 +        r->ecx = 1;
   7.285 +        r->esi = r->edi = r->ebp =
   7.286 +        r->edx = 0; /* floppy disk */
   7.287 +        r->cs = r->ss = r->ds = r->es = 0;
   7.288 +        r->eflags = VIF_MASK;
   7.289 +        ret = read(fd, seg_to_linear(0x0, 0x7c00), 0x200);
   7.290 +        if (lseek(fd, 0, SEEK_END) > 4*1024*1024)
   7.291 +            r->edx = 0x80; /* hard disk */
   7.292 +        close(fd);
   7.293 +        if (ret != 0x200 ||
   7.294 +            *seg_to_linear(0x0, 0x7dfe) != 0x55 ||
   7.295 +            *seg_to_linear(0x0, 0x7dff) != 0xaa) {
   7.296 +            fprintf(stderr,"No boot sector.\n");
   7.297 +            fd = -1;
   7.298 +        }
   7.299 +    }
   7.300 +    return fd;
   7.301 +}
   7.302 +
   7.303 +/* return the PSP or -1 if error */
   7.304 +int load_exe(ExecParamBlock *blk, const char *filename,
   7.305 +             int psp, uint32_t *pfile_size)
   7.306 +{
   7.307 +    int fd, size, base;
   7.308 +    struct {
   7.309 +    	uint16_t signature;		// 0x5A4D 'MZ'
   7.310 +    	uint16_t bytes_in_last_block;
   7.311 +    	uint16_t blocks_in_file;	
   7.312 +    	uint16_t num_relocs;	
   7.313 +    	uint16_t header_paragraphs;	// Size of header
   7.314 +    	uint16_t min_extra_paragraphs;	// BSS size
   7.315 +    	uint16_t max_extra_paragraphs;
   7.316 +    	uint16_t ss;			// Initial (relative) SS value
   7.317 +    	uint16_t sp;			// Initial SP value
   7.318 +    	uint16_t checksum;
   7.319 +    	uint16_t ip;			// Initial IP value
   7.320 +    	uint16_t cs;			// Initial (relative) CS value
   7.321 +    	uint16_t reloc_table_offset;
   7.322 +    	uint16_t overlay_number;
   7.323 +    } header;
   7.324 +    struct {
   7.325 +    	uint16_t offset;
   7.326 +    	uint16_t segment;
   7.327 +    } rel;
   7.328 +
   7.329 +    /* load the MSDOS .exe executable */
   7.330 +    fd = open(filename, O_RDONLY);
   7.331 +    if (fd < 0) {
   7.332 +        return -1;
   7.333 +    }
   7.334 +    if (read(fd, &header, sizeof(header)) != sizeof(header)) {
   7.335 +        close(fd);
   7.336 +        return -1;
   7.337 +    }
   7.338 +    
   7.339 +    memset(seg_to_linear(psp, 0x100), 0, 65536 - 0x100);
   7.340 +  
   7.341 +    size = (header.blocks_in_file * 512) - (header.header_paragraphs * 16) + 
   7.342 +    	(header.bytes_in_last_block ? header.bytes_in_last_block - 512 : 0);
   7.343 +    header.min_extra_paragraphs += (size-1)/16;
   7.344 +    
   7.345 +    /* address of last segment allocated */
   7.346 +    *(uint16_t *)seg_to_linear(psp, 2) = psp + header.min_extra_paragraphs;
   7.347 +    
   7.348 +    if (pfile_size)
   7.349 +        *pfile_size = size;
   7.350 +
   7.351 +    if (mem_resize(psp, header.min_extra_paragraphs) < 0 ||
   7.352 +    	lseek(fd, header.header_paragraphs * 16, SEEK_SET) < 0 ||
   7.353 +        read(fd, seg_to_linear(psp, 0x100), size) != size ||
   7.354 +        lseek(fd, header.reloc_table_offset, SEEK_SET) < 0) {
   7.355 +        close(fd);
   7.356 +        return -1;
   7.357 +    }
   7.358 +
   7.359 +    base = psp + 16;
   7.360 +    while (header.num_relocs-- && read(fd, &rel, sizeof(rel)) == sizeof(rel))
   7.361 +    	if (rel.segment != 0 || rel.offset != 0)
   7.362 +    	    * (uint16_t *) seg_to_linear(base + rel.segment, rel.offset) += base;
   7.363 +    close(fd);
   7.364 +
   7.365 +    blk->cs = base + header.cs;
   7.366 +    blk->ip = header.ip;
   7.367 +    blk->ss = base + header.ss;
   7.368 +    blk->sp = header.sp - 6;
   7.369 +
   7.370 +    /* push return far address */
   7.371 +    *(uint16_t *)seg_to_linear(blk->ss, blk->sp + 4) = psp;
   7.372 +
   7.373 +    return psp;
   7.374 +}
   7.375 +
   7.376 +/* return the PSP or -1 if error */
   7.377 +int load_com(ExecParamBlock *blk, const char *filename, uint32_t *pfile_size,
   7.378 +             int argc, char **argv)
   7.379 +{
   7.380 +    int psp, fd, ret;
   7.381 +
   7.382 +    /* load the MSDOS .com executable */
   7.383 +    fd = open(filename, O_RDONLY);
   7.384 +    if (fd < 0) {
   7.385 +        return -1;
   7.386 +    }
   7.387 +    psp = mem_malloc(65536 / 16, NULL);
   7.388 +    ret = read(fd, seg_to_linear(psp, 0x100), 65536 - 0x100);
   7.389 +    close(fd);
   7.390 +    if (ret <= 0) {
   7.391 +        mem_free(psp);
   7.392 +        return -1;
   7.393 +    }
   7.394 +    if (pfile_size)
   7.395 +        *pfile_size = ret;
   7.396 +    
   7.397 +    /* reset the PSP */
   7.398 +    memset(seg_to_linear(psp, 0), 0, 0x100);
   7.399 +
   7.400 +    *seg_to_linear(psp, 0) = 0xcd; /* int $0x20 */
   7.401 +    *seg_to_linear(psp, 1) = 0x20;
   7.402 +    /* address of last segment allocated */
   7.403 +    *(uint16_t *)seg_to_linear(psp, 2) = psp + 0xfff;
   7.404 +
   7.405 +    if (argc) {
   7.406 +        int i, p;
   7.407 +        char *s;
   7.408 +        /* set the command line */
   7.409 +        p = 0x81;
   7.410 +        for(i = 2; i < argc; i++) {
   7.411 +            if (p >= 0xff)
   7.412 +                break;
   7.413 +            *seg_to_linear(psp, p++) = ' ';
   7.414 +            s = argv[i];
   7.415 +            while (*s) {
   7.416 +                if (p >= 0xff)
   7.417 +                    break;
   7.418 +                *seg_to_linear(psp, p++) = *s++;
   7.419 +            }
   7.420 +        }
   7.421 +        *seg_to_linear(psp, p) = '\r';
   7.422 +        *seg_to_linear(psp, 0x80) = p - 0x81;
   7.423 +    }
   7.424 +    else {
   7.425 +        int len;
   7.426 +        /* copy the command line */
   7.427 +        len = *seg_to_linear(blk->cmdtail_seg, blk->cmdtail_off);
   7.428 +        memcpy(seg_to_linear(psp, 0x80), 
   7.429 +               seg_to_linear(blk->cmdtail_seg, blk->cmdtail_off), len + 2);
   7.430 +    }
   7.431 +
   7.432 +    blk->sp = 0xfffc;
   7.433 +    blk->ip = 0x100;
   7.434 +    blk->cs = blk->ss = psp;
   7.435 +
   7.436 +    if (*(uint16_t *)seg_to_linear(psp, 0x100) == 0x5A4D)
   7.437 +        psp = load_exe(blk, filename, psp, pfile_size);
   7.438 +    
   7.439 +    /* push ax value */
   7.440 +    *(uint16_t *)seg_to_linear(blk->ss, blk->sp) = 0;
   7.441 +    /* push return address to 0 */
   7.442 +    *(uint16_t *)seg_to_linear(blk->ss, blk->sp + 2) = 0;
   7.443 + 
   7.444 +    return psp;
   7.445 +}
   7.446 +
   7.447 +
   7.448 +void unsupported_function(struct vm86_regs *r, uint8_t num, uint8_t ah)
   7.449 +{
   7.450 +    fprintf(stderr, "int 0x%02x: unsupported function 0x%02x\n", num, ah);
   7.451 +    dump_regs(r);
   7.452 +    set_error(r, 0x01); /* function number invalid */
   7.453 +}
   7.454 +
   7.455 +/* Open hard disk image ./hd[0-7] / floppy image ./fd[0-7] or /dev/fd[0-7] */
   7.456 +int open_disk(struct vm86_regs *r)
   7.457 +{
   7.458 +    int fd = -1, drive = r->edx & 0xff;
   7.459 +    char filename[9], n = '0' + (drive & 7);
   7.460 +    if (drive > 127) {
   7.461 +        strcpy(filename,"hd0");
   7.462 +        filename[2] = n;
   7.463 +    }
   7.464 +    else {
   7.465 +        strcpy(filename,"/dev/fd0");
   7.466 +        filename[7] = n;
   7.467 +        fd = open(filename+5, O_RDONLY);
   7.468 +    }
   7.469 +    if (fd < 0)
   7.470 +        fd = open(filename, O_RDONLY);
   7.471 +    return fd;
   7.472 +}
   7.473 +
   7.474 +
   7.475 +void read_sectors(int fd, struct vm86_regs *r, int first_sector, 
   7.476 +                  int sector_count, void *buffer) 
   7.477 +{
   7.478 +    int drive = r->edx & 0xff;
   7.479 +    r->eax &= ~0xff00;
   7.480 +    r->eax |= 0x0400; /* sector not found */
   7.481 +    r->eflags |= CF_MASK;
   7.482 +    if (fd >= 0) {
   7.483 +        static struct stat st;
   7.484 +        first_sector <<= 9;
   7.485 +        sector_count <<= 9;
   7.486 +    	if (drive < 8 && fstat(fd, &st) == 0) {
   7.487 +            static ino_t inodes[8];
   7.488 +            ino_t last = inodes[drive];
   7.489 +            inodes[drive] = st.st_ino;
   7.490 +            if (last && last != st.st_ino) {
   7.491 +                set_error(r, 0x0600); /* floppy disk swap */
   7.492 +                goto failed;
   7.493 +            }
   7.494 +    	}
   7.495 +        if (lseek(fd, first_sector, SEEK_CUR) >= 0 &&
   7.496 +            read(fd, buffer, sector_count) == sector_count) {
   7.497 +            r->eax &= ~0xff00;
   7.498 +            r->eflags &= ~CF_MASK;
   7.499 +        }
   7.500 +    failed:
   7.501 +        close(fd);
   7.502 +    }
   7.503 +}
   7.504 +
   7.505 +void do_int10(struct vm86_regs *r)
   7.506 +{
   7.507 +    uint8_t ah;
   7.508 +    
   7.509 +    ah = (r->eax >> 8);
   7.510 +    switch(ah) {
   7.511 +    case 0x0E: /* write char */
   7.512 +        {
   7.513 +            uint8_t c = r->eax;
   7.514 +            write(1, &c, 1);
   7.515 +        }
   7.516 +        break;
   7.517 +    default:
   7.518 +        unsupported_function(r, 0x10, ah);
   7.519 +    }
   7.520 +}
   7.521 +
   7.522 +void do_int13(struct vm86_regs *r)
   7.523 +{
   7.524 +    uint8_t ah;
   7.525 +    
   7.526 +    ah = (r->eax >> 8);
   7.527 +    switch(ah) {
   7.528 +    case 0x00: /* reset disk */
   7.529 +        {
   7.530 +            r->eax &= ~0xff00; /* success */
   7.531 +            r->eflags &= ~CF_MASK;
   7.532 +        }
   7.533 +        break;
   7.534 +    case 0x02: /* read disk CHS */
   7.535 +        {
   7.536 +            int fd, c, h, s, heads, sectors, cylinders;
   7.537 +            long size;
   7.538 +            fd = open_disk(r);
   7.539 +            if (fd >= 0) {
   7.540 +                size = lseek(fd, 0, SEEK_END) / 512;
   7.541 +                if ((r->edx & 0xff) > 127) {
   7.542 +        	    sectors = 63;
   7.543 +                    if (size % sectors)
   7.544 +        	        sectors = 62;
   7.545 +                    if (size % sectors)
   7.546 +        	        sectors = 32;
   7.547 +                    if (size % sectors)
   7.548 +        	        sectors = 17;
   7.549 +                    if (size % sectors)
   7.550 +                        fd = -1;
   7.551 +                    size /= sectors;
   7.552 +        	    for (heads = 256; size % heads; heads--);
   7.553 +        	    cylinders = size / heads;
   7.554 +                }
   7.555 +                else {
   7.556 +                    int i;
   7.557 +        	    heads = 1 + (size > 256*2);
   7.558 +        	    cylinders = 40 * (1 + (size > 512*2));
   7.559 +        	    size /= heads;
   7.560 +        	    for (i = 0; i < 5; i++)
   7.561 +        	        if (size % (cylinders + i) == 0) break;
   7.562 +        	    if (i == 5)
   7.563 +        	    	fd = -1;
   7.564 +        	    cylinders += i;
   7.565 +        	    sectors = size / cylinders;
   7.566 +                }
   7.567 +            }
   7.568 +            c = ((r->ecx & 0xC0) << 2) | ((r->ecx >> 8) & 0xff);
   7.569 +            h = (r->edx >> 8) & 0xff;
   7.570 +            s = (r->ecx & 0x3f) -1;
   7.571 +            if (fd < 0 || c >= cylinders || h >= heads || s >= sectors) {
   7.572 +                set_error(r, 0x0400); /* sector not found */
   7.573 +                break;
   7.574 +            }
   7.575 +            read_sectors(fd, r, (((c * heads) + h) * sectors) + s,
   7.576 +                         r->eax & 0xff, seg_to_linear(r->es, r->ebx));
   7.577 +        }
   7.578 +        break;
   7.579 +    case 0x42: /* read disk LBA */
   7.580 +        {
   7.581 +            uint16_t *packet = (uint16_t *) seg_to_linear(r->ds, r-> esi);
   7.582 +            uint8_t *to = seg_to_linear(packet[3], packet[2]);
   7.583 +            if ((packet[3] & packet[2]) == 0xffff)
   7.584 +            	to = * (uint8_t **) &packet[8]; 
   7.585 +            if (packet[0] != 0x0010 && packet[0] != 0x0018)
   7.586 +                goto unsupported;
   7.587 +            read_sectors(open_disk(r), r, * (uint32_t *) &packet[4], packet[1], to);
   7.588 +        }
   7.589 +        break;
   7.590 +    default:
   7.591 +    unsupported:
   7.592 +        unsupported_function(r, 0x13, ah);
   7.593 +    }
   7.594 +}
   7.595 +
   7.596 +void do_int15(struct vm86_regs *r)
   7.597 +{
   7.598 +    uint8_t ah;
   7.599 +    
   7.600 +    ah = (r->eax >> 8);
   7.601 +    switch(ah) {
   7.602 +    case 0x87: /* move memory */
   7.603 +    	/* XXX */
   7.604 +        break;
   7.605 +    default:
   7.606 +        unsupported_function(r, 0x15, ah);
   7.607 +    }
   7.608 +}
   7.609 +
   7.610 +void do_int16(struct vm86_regs *r)
   7.611 +{
   7.612 +    static uint16_t last_ax, hold_char;
   7.613 +    struct termios termios_def, termios_raw;
   7.614 +    uint8_t ah;
   7.615 +    
   7.616 +    ah = (r->eax >> 8);
   7.617 +    tcgetattr(0, &termios_def);
   7.618 +    termios_raw = termios_def;
   7.619 +    cfmakeraw(&termios_raw);
   7.620 +    tcsetattr(0, TCSADRAIN, &termios_raw);
   7.621 +    switch(ah) {
   7.622 +    case 0x01: /* test keyboard */
   7.623 +        {
   7.624 +            int count;
   7.625 +            r->eflags &= ~ZF_MASK;
   7.626 +            if (hold_char) {
   7.627 +                r->eax &= ~0xffff;
   7.628 +                r->eax |= last_ax;
   7.629 +                break;
   7.630 +            }
   7.631 +    	    if (ioctl(0, FIONREAD, &count) < 0 || count == 0) {
   7.632 +                r->eflags |= ZF_MASK;
   7.633 +                break;
   7.634 +            }
   7.635 +            hold_char = 2;
   7.636 +        }
   7.637 +    case 0x00: /* read keyboard */
   7.638 +        {
   7.639 +            uint8_t c;
   7.640 +            if (hold_char)
   7.641 +            	hold_char--;
   7.642 +            read(0, &c, 1);
   7.643 +            if (c == 3) {
   7.644 +                tcsetattr(0, TCSADRAIN, &termios_def);
   7.645 +                exit(0);
   7.646 +            }
   7.647 +            if (c == 10)
   7.648 +            	c = 13;
   7.649 +            r->eax &= ~0xffff;
   7.650 +            r->eax |= last_ax = c;
   7.651 +            /* XXX ah = scan code */
   7.652 +        }
   7.653 +        break;
   7.654 +    default:
   7.655 +        unsupported_function(r, 0x16, ah);
   7.656 +    }
   7.657 +    tcsetattr(0, TCSADRAIN, &termios_def);
   7.658 +}
   7.659 +
   7.660 +void do_int1a(struct vm86_regs *r)
   7.661 +{
   7.662 +    uint8_t ah;
   7.663 +    
   7.664 +    ah = (r->eax >> 8);
   7.665 +    switch(ah) {
   7.666 +    case 0x00: /* GET SYSTEM TIME */
   7.667 +        {
   7.668 +            uint16_t *timer = (uint16_t *) seg_to_linear(0, 0x46C);
   7.669 +            r->ecx &= ~0xffff;
   7.670 +            r->ecx |= *timer++;
   7.671 +            r->edx &= ~0xffff;
   7.672 +            r->edx |= *timer;
   7.673 +            r->eax &= ~0xff;
   7.674 +        }
   7.675 +        break;
   7.676 +    default:
   7.677 +        unsupported_function(r, 0x1a, ah);
   7.678 +    }
   7.679 +}
   7.680 +
   7.681 +void do_int20(struct vm86_regs *r)
   7.682 +{
   7.683 +    /* terminate program */
   7.684 +    exit(0);
   7.685 +}
   7.686 +
   7.687 +void do_int21(struct vm86_regs *r)
   7.688 +{
   7.689 +    uint8_t ah;
   7.690 +    
   7.691 +    ah = (r->eax >> 8);
   7.692 +    switch(ah) {
   7.693 +    case 0x00: /* exit */
   7.694 +        exit(0);
   7.695 +    case 0x02: /* write char */
   7.696 +        {
   7.697 +            uint8_t c = r->edx;
   7.698 +            write(1, &c, 1);
   7.699 +        }
   7.700 +        break;
   7.701 +    case 0x09: /* write string */
   7.702 +        {
   7.703 +            uint8_t c;
   7.704 +            int offset;
   7.705 +            offset = r->edx;
   7.706 +            for(;;) {
   7.707 +                c = *seg_to_linear(r->ds, offset);
   7.708 +                if (c == '$')
   7.709 +                    break;
   7.710 +                write(1, &c, 1);
   7.711 +                offset++;
   7.712 +            }
   7.713 +            r->eax = (r->eax & ~0xff) | '$';
   7.714 +        }
   7.715 +        break;
   7.716 +    case 0x0a: /* buffered input */
   7.717 +        {
   7.718 +            int max_len, cur_len, ret;
   7.719 +            uint8_t ch;
   7.720 +            uint16_t off;
   7.721 +
   7.722 +            /* XXX: should use raw mode to avoid sending the CRLF to
   7.723 +               the terminal */
   7.724 +            off = r->edx & 0xffff;
   7.725 +            max_len = *seg_to_linear(r->ds, off);
   7.726 +            cur_len = 0;
   7.727 +            while (cur_len < max_len) {
   7.728 +                ret = read(0, &ch, 1);
   7.729 +                if (ret < 0) {
   7.730 +                    if (errno != EINTR && errno != EAGAIN)
   7.731 +                        break;
   7.732 +                } else if (ret == 0) {
   7.733 +                    break;
   7.734 +                } else {
   7.735 +                    if (ch == '\n')
   7.736 +                        break;
   7.737 +                }
   7.738 +                *seg_to_linear(r->ds, off + 2 + cur_len++) = ch;
   7.739 +            }
   7.740 +            *seg_to_linear(r->ds, off + 1) = cur_len;
   7.741 +            *seg_to_linear(r->ds, off + 2 + cur_len) = '\r';
   7.742 +        }
   7.743 +        break;
   7.744 +    case 0x25: /* set interrupt vector */
   7.745 +        {
   7.746 +            uint16_t *ptr;
   7.747 +            ptr = (uint16_t *)seg_to_linear(0, (r->eax & 0xff) * 4);
   7.748 +            ptr[0] = r->edx;
   7.749 +            ptr[1] = r->ds;
   7.750 +        }
   7.751 +        break;
   7.752 +    case 0x29: /* parse filename into FCB */
   7.753 +#if 0
   7.754 +        /* not really needed */
   7.755 +        {
   7.756 +            const uint8_t *p, *p_start;
   7.757 +            uint8_t file[8], ext[3]; 
   7.758 +            FCB *fcb;
   7.759 +            int file_len, ext_len, has_wildchars, c, drive_num;
   7.760 +            
   7.761 +            /* XXX: not complete at all */
   7.762 +            fcb = (FCB *)seg_to_linear(r->es, r->edi);
   7.763 +            printf("ds=0x%x si=0x%lx\n", r->ds, r->esi);
   7.764 +            p_start = (const uint8_t *)seg_to_linear(r->ds, r->esi);
   7.765 +
   7.766 +            p = p_start;
   7.767 +            has_wildchars = 0;
   7.768 +
   7.769 +            /* drive */
   7.770 +            if (isalpha(p[0]) && p[1] == ':') {
   7.771 +                drive_num = toupper(p[0]) - 'A' + 1;
   7.772 +                p += 2;
   7.773 +            } else {
   7.774 +                drive_num = 0;
   7.775 +            }
   7.776 +
   7.777 +            /* filename */
   7.778 +            file_len = 0;
   7.779 +            for(;;) {
   7.780 +                c = *p;
   7.781 +                if (!(c >= 33 && c <= 126))
   7.782 +                    break;
   7.783 +                if (c == '.')
   7.784 +                    break;
   7.785 +                if (c == '*' || c == '?')
   7.786 +                    has_wildchars = 1;
   7.787 +                if (file_len < 8)
   7.788 +                    file[file_len++] = c;
   7.789 +            }
   7.790 +            memset(file + file_len, ' ', 8 - file_len);
   7.791 +
   7.792 +            /* extension */
   7.793 +            ext_len = 0;
   7.794 +            if (*p == '.') {
   7.795 +                for(;;) {
   7.796 +                    c = *p;
   7.797 +                    if (!(c >= 33 && c <= 126))
   7.798 +                        break;
   7.799 +                    if (c == '*' || c == '?')
   7.800 +                        has_wildchars = 1;
   7.801 +                    ext[ext_len++] = c;
   7.802 +                    if (ext_len >= 3)
   7.803 +                        break;
   7.804 +                }
   7.805 +            }
   7.806 +            memset(ext + ext_len, ' ', 3 - ext_len);
   7.807 +
   7.808 +#if 0
   7.809 +            {
   7.810 +                printf("drive=%d file=%8s ext=%3s\n",
   7.811 +                       drive_num, file, ext);
   7.812 +            }
   7.813 +#endif
   7.814 +            if (drive_num == 0 && r->eax & (1 << 1)) {
   7.815 +                /* keep drive */
   7.816 +            } else {
   7.817 +                fcb->drive_num = drive_num; /* default drive */
   7.818 +            }
   7.819 +
   7.820 +            if (file_len == 0 && r->eax & (1 << 2)) {
   7.821 +                /* keep */
   7.822 +            } else {
   7.823 +                memcpy(fcb->file_name, file, 8);
   7.824 +            }
   7.825 +
   7.826 +            if (ext_len == 0 && r->eax & (1 << 3)) {
   7.827 +                /* keep */
   7.828 +            } else {
   7.829 +                memcpy(fcb->file_ext, ext, 3);
   7.830 +            }
   7.831 +            r->eax = (r->eax & ~0xff) | has_wildchars;
   7.832 +            r->esi = (r->esi & ~0xffff) | ((r->esi + (p - p_start)) & 0xffff);
   7.833 +        }
   7.834 +#endif
   7.835 +        break;
   7.836 +    case 0x2A: /* get system date */
   7.837 +        {
   7.838 +            time_t t = time(NULL);
   7.839 +            struct tm *now=localtime(&t);
   7.840 +            
   7.841 +            r->ecx = now->tm_year;
   7.842 +            r->edx = (now->tm_mon * 256) + now->tm_mday;
   7.843 +            r->eax = now->tm_wday;;
   7.844 +        }
   7.845 +        break;
   7.846 +    case 0x2C: /* get system time */
   7.847 +        {
   7.848 +            time_t t = time(NULL);
   7.849 +            struct tm *now=localtime(&t);
   7.850 +            struct timeval tim;
   7.851 +            
   7.852 +            gettimeofday(&tim, NULL);
   7.853 +            r->edx = (now->tm_hour * 256) + now->tm_min;
   7.854 +            r->edx = (tim.tv_sec * 256) + tim.tv_usec/10000;
   7.855 +        }
   7.856 +        break;
   7.857 +    case 0x30: /* get dos version */
   7.858 +        {
   7.859 +            int major, minor, serial, oem;
   7.860 +            /* XXX: return correct value for FreeDOS */
   7.861 +            major = 0x03;
   7.862 +            minor = 0x31;
   7.863 +            serial = 0x123456;
   7.864 +            oem = 0x66;
   7.865 +            r->eax = (r->eax & ~0xffff) | major | (minor << 8);
   7.866 +            r->ecx = (r->ecx & ~0xffff) | (serial & 0xffff);
   7.867 +            r->ebx = (r->ebx & ~0xffff) | (serial & 0xff) | (0x66 << 8);
   7.868 +        }
   7.869 +        break;
   7.870 +    case 0x35: /* get interrupt vector */
   7.871 +        {
   7.872 +            uint16_t *ptr;
   7.873 +            ptr = (uint16_t *)seg_to_linear(0, (r->eax & 0xff) * 4);
   7.874 +            r->ebx = (r->ebx & ~0xffff) | ptr[0];
   7.875 +            r->es = ptr[1];
   7.876 +        }
   7.877 +        break;
   7.878 +    case 0x37: 
   7.879 +        {
   7.880 +            switch(r->eax & 0xff) {
   7.881 +            case 0x00: /* get switch char */
   7.882 +                r->eax = (r->eax & ~0xff) | 0x00;
   7.883 +                r->edx = (r->edx & ~0xff) | '/';
   7.884 +                break;
   7.885 +            default:
   7.886 +                goto unsupported;
   7.887 +            }
   7.888 +        }
   7.889 +        break;
   7.890 +    case 0x3c: /* create or truncate file */
   7.891 +        {
   7.892 +            char filename[1024];
   7.893 +            int fd, h, flags;
   7.894 +
   7.895 +            h = get_new_handle();
   7.896 +            if (h < 0) {
   7.897 +                set_error(r, 0x04); /* too many open files */
   7.898 +            } else {
   7.899 +                get_filename(r, filename, sizeof(filename));
   7.900 +                if (r->ecx & 1)
   7.901 +                    flags = 0444; /* read-only */
   7.902 +                else
   7.903 +                    flags = 0777;
   7.904 +                fd = open(filename, O_RDWR | O_TRUNC | O_CREAT, flags);
   7.905 +#ifdef DUMP_INT21
   7.906 +                printf("int21: create: file='%s' cx=0x%04x ret=%d\n", 
   7.907 +                       filename, (int)(r->ecx & 0xffff), h);
   7.908 +#endif
   7.909 +                if (fd < 0) {
   7.910 +                    set_error(r, 0x03); /* path not found */
   7.911 +                } else {
   7.912 +                    dos_files[h].fd = fd;
   7.913 +                    set_error(r, 0);
   7.914 +                    r->eax = (r->eax & ~0xffff) | h;
   7.915 +                }
   7.916 +            }
   7.917 +        }
   7.918 +        break;
   7.919 +    case 0x3d: /* open file */
   7.920 +        {
   7.921 +            char filename[1024];
   7.922 +            int fd, h;
   7.923 +
   7.924 +            h = get_new_handle();
   7.925 +            if (h < 0) {
   7.926 +                set_error(r, 0x04); /* too many open files */
   7.927 +            } else {
   7.928 +                get_filename(r, filename, sizeof(filename));
   7.929 +#ifdef DUMP_INT21
   7.930 +                printf("int21: open: file='%s' al=0x%02x ret=%d\n", 
   7.931 +                       filename, (int)(r->eax & 0xff), h);
   7.932 +#endif
   7.933 +                fd = open(filename, r->eax & 3);
   7.934 +                if (fd < 0) {
   7.935 +                    set_error(r, 0x02); /* file not found */
   7.936 +                } else {
   7.937 +                    dos_files[h].fd = fd;
   7.938 +                    set_error(r, 0);
   7.939 +                    r->eax = (r->eax & ~0xffff) | h;
   7.940 +                }
   7.941 +            }
   7.942 +        }
   7.943 +        break;
   7.944 +    case 0x3e: /* close file */
   7.945 +        {
   7.946 +            DOSFile *fh = get_file(r->ebx & 0xffff);
   7.947 +#ifdef DUMP_INT21
   7.948 +            printf("int21: close fd=%d\n", (int)(r->ebx & 0xffff));
   7.949 +#endif
   7.950 +            if (!fh) {
   7.951 +                set_error(r, 0x06); /* invalid handle */
   7.952 +            } else {
   7.953 +                close(fh->fd);
   7.954 +                fh->fd = -1;
   7.955 +                set_error(r, 0);
   7.956 +            }
   7.957 +        }
   7.958 +        break;
   7.959 +    case 0x3f: /* read */
   7.960 +        {
   7.961 +            DOSFile *fh = get_file(r->ebx & 0xffff);
   7.962 +            int n, ret;
   7.963 +
   7.964 +            if (!fh) {
   7.965 +                set_error(r, 0x06); /* invalid handle */
   7.966 +            } else {
   7.967 +                n = r->ecx & 0xffff;
   7.968 +                for(;;) {
   7.969 +                    ret = read(fh->fd, 
   7.970 +                               seg_to_linear(r->ds, r->edx), n);
   7.971 +                    if (ret < 0) {
   7.972 +                        if (errno != EINTR && errno != EAGAIN)
   7.973 +                            break;
   7.974 +                    } else {
   7.975 +                        break;
   7.976 +                    }
   7.977 +                }
   7.978 +#ifdef DUMP_INT21
   7.979 +                printf("int21: read: fd=%d n=%d ret=%d\n", 
   7.980 +                       (int)(r->ebx & 0xffff), n, ret);
   7.981 +#endif
   7.982 +                if (ret < 0) {
   7.983 +                    set_error(r, 0x05); /* acces denied */
   7.984 +                } else {
   7.985 +                    r->eax = (r->eax & ~0xffff) | ret;
   7.986 +                    set_error(r, 0);
   7.987 +                }
   7.988 +            }
   7.989 +        }
   7.990 +        break;
   7.991 +    case 0x40: /* write */
   7.992 +        {
   7.993 +            DOSFile *fh = get_file(r->ebx & 0xffff);
   7.994 +            int n, ret, pos;
   7.995 +            
   7.996 +            if (!fh) {
   7.997 +                set_error(r, 0x06); /* invalid handle */
   7.998 +            } else {
   7.999 +                n = r->ecx & 0xffff;
  7.1000 +                if (n == 0) {
  7.1001 +                    /* truncate */
  7.1002 +                    pos = lseek(fh->fd, 0, SEEK_CUR);
  7.1003 +                    if (pos >= 0) {
  7.1004 +                        ret = ftruncate(fh->fd, pos);
  7.1005 +                    } else {
  7.1006 +                        ret = -1;
  7.1007 +                    }
  7.1008 +                } else {
  7.1009 +                    for(;;) {
  7.1010 +                        ret = write(fh->fd, 
  7.1011 +                                    seg_to_linear(r->ds, r->edx), n);
  7.1012 +                        if (ret < 0) {
  7.1013 +                            if (errno != EINTR && errno != EAGAIN)
  7.1014 +                                break;
  7.1015 +                        } else {
  7.1016 +                            break;
  7.1017 +                        }
  7.1018 +                    }
  7.1019 +                }
  7.1020 +#ifdef DUMP_INT21
  7.1021 +                printf("int21: write: fd=%d n=%d ret=%d\n", 
  7.1022 +                       (int)(r->ebx & 0xffff), n, ret);
  7.1023 +#endif
  7.1024 +                if (ret < 0) {
  7.1025 +                    set_error(r, 0x05); /* acces denied */
  7.1026 +                } else {
  7.1027 +                    r->eax = (r->eax & ~0xffff) | ret;
  7.1028 +                    set_error(r, 0);
  7.1029 +                }
  7.1030 +            }
  7.1031 +        }
  7.1032 +        break;
  7.1033 +    case 0x41: /* unlink */
  7.1034 +        {
  7.1035 +            char filename[1024];
  7.1036 +            get_filename(r, filename, sizeof(filename));
  7.1037 +            if (unlink(filename) < 0) {
  7.1038 +                set_error(r, 0x02); /* file not found */
  7.1039 +            } else {
  7.1040 +                set_error(r, 0);
  7.1041 +            }
  7.1042 +        }
  7.1043 +        break;
  7.1044 +    case 0x42: /* lseek */
  7.1045 +        {
  7.1046 +            DOSFile *fh = get_file(r->ebx & 0xffff);
  7.1047 +            int pos, ret;
  7.1048 +            
  7.1049 +            if (!fh) {
  7.1050 +                set_error(r, 0x06); /* invalid handle */
  7.1051 +            } else {
  7.1052 +                pos = ((r->ecx & 0xffff) << 16) | (r->edx & 0xffff);
  7.1053 +                ret = lseek(fh->fd, pos, r->eax & 0xff);
  7.1054 +#ifdef DUMP_INT21
  7.1055 +                printf("int21: lseek: fd=%d pos=%d whence=%d ret=%d\n", 
  7.1056 +                       (int)(r->ebx & 0xffff), pos, (uint8_t)r->eax, ret);
  7.1057 +#endif
  7.1058 +                if (ret < 0) {
  7.1059 +                    set_error(r, 0x01); /* function number invalid */
  7.1060 +                } else {
  7.1061 +                    r->edx = (r->edx & ~0xffff) | ((unsigned)ret >> 16);
  7.1062 +                    r->eax = (r->eax & ~0xffff) | (ret & 0xffff);
  7.1063 +                    set_error(r, 0);
  7.1064 +                }
  7.1065 +            }
  7.1066 +        }
  7.1067 +        break;
  7.1068 +    case 0x44: /* ioctl */
  7.1069 +        switch(r->eax & 0xff) {
  7.1070 +        case 0x00: /* get device information */
  7.1071 +            {
  7.1072 +                DOSFile *fh = get_file(r->ebx & 0xffff);
  7.1073 +                int ret;
  7.1074 +                
  7.1075 +                if (!fh) {
  7.1076 +                    set_error(r, 0x06); /* invalid handle */
  7.1077 +                } else {
  7.1078 +                    ret = 0;
  7.1079 +                    if (isatty(fh->fd)) {
  7.1080 +                        ret |= 0x80;
  7.1081 +                        if (fh->fd == 0)
  7.1082 +                            ret |= (1 << 0);
  7.1083 +                        else
  7.1084 +                            ret |= (1 << 1);
  7.1085 +                    }
  7.1086 +                    r->edx = (r->edx & ~0xffff) | ret;
  7.1087 +                    set_error(r, 0);
  7.1088 +                }
  7.1089 +            }
  7.1090 +            break;
  7.1091 +        default:
  7.1092 +            goto unsupported;
  7.1093 +        }
  7.1094 +        break;
  7.1095 +    case 0x48: /* allocate memory */
  7.1096 +        {
  7.1097 +            int ret, max_size;
  7.1098 +#ifdef DUMP_INT21
  7.1099 +            printf("int21: allocate memory: size=0x%04x\n", (uint16_t)r->ebx);
  7.1100 +#endif
  7.1101 +            ret = mem_malloc(r->ebx & 0xffff, &max_size);
  7.1102 +            if (ret < 0) {
  7.1103 +                set_error(r, 0x08); /* insufficient memory*/
  7.1104 +            } else {
  7.1105 +                r->eax = (r->eax & ~0xffff) | ret;
  7.1106 +                r->ebx = (r->ebx & ~0xffff) | max_size;
  7.1107 +                set_error(r, 0);
  7.1108 +            }
  7.1109 +        }
  7.1110 +        break;
  7.1111 +    case 0x49: /* free memory */
  7.1112 +        {
  7.1113 +#ifdef DUMP_INT21
  7.1114 +            printf("int21: free memory: block=0x%04x\n", r->es);
  7.1115 +#endif
  7.1116 +            if (mem_free(r->es) < 0) {
  7.1117 +                set_error(r, 0x09); /* memory block address invalid */
  7.1118 +            } else {
  7.1119 +                set_error(r, 0);
  7.1120 +            }
  7.1121 +        }
  7.1122 +        break;
  7.1123 +    case 0x4a: /* resize memory block */
  7.1124 +        {
  7.1125 +            int ret;
  7.1126 +#ifdef DUMP_INT21
  7.1127 +            printf("int21: resize memory block: block=0x%04x size=0x%04x\n", 
  7.1128 +                   r->es, (uint16_t)r->ebx);
  7.1129 +#endif
  7.1130 +            ret = mem_resize(r->es, r->ebx & 0xffff);
  7.1131 +            if (ret < 0) {
  7.1132 +                set_error(r, 0x08); /* insufficient memory*/
  7.1133 +            } else {
  7.1134 +                r->ebx = (r->ebx & ~0xffff) | ret;
  7.1135 +                set_error(r, 0);
  7.1136 +            }
  7.1137 +        }
  7.1138 +        break;
  7.1139 +    case 0x4b: /* load program */
  7.1140 +        {
  7.1141 +            char filename[1024];
  7.1142 +            ExecParamBlock *blk;
  7.1143 +            int ret;
  7.1144 +
  7.1145 +            if ((r->eax & 0xff) != 0x01) /* only load */
  7.1146 +                goto unsupported;
  7.1147 +            get_filename(r, filename, sizeof(filename));
  7.1148 +            blk = (ExecParamBlock *)seg_to_linear(r->es, r->ebx);
  7.1149 +            ret = load_com(blk, filename, NULL, 0, NULL);
  7.1150 +            if (ret < 0) {
  7.1151 +                set_error(r, 0x02); /* file not found */
  7.1152 +            } else {
  7.1153 +                cur_psp = ret;
  7.1154 +                set_error(r, 0);
  7.1155 +            }
  7.1156 +        }
  7.1157 +        break;
  7.1158 +    case 0x4c: /* exit with return code */
  7.1159 +        exit(r->eax & 0xff);
  7.1160 +        break;
  7.1161 +    case 0x50: /* set PSP address */
  7.1162 +#ifdef DUMP_INT21
  7.1163 +        printf("int21: set PSP: 0x%04x\n", (uint16_t)r->ebx);
  7.1164 +#endif
  7.1165 +        cur_psp = r->ebx;
  7.1166 +        break;
  7.1167 +    case 0x51: /* get PSP address */
  7.1168 +#ifdef DUMP_INT21
  7.1169 +        printf("int21: get PSP: ret=0x%04x\n", cur_psp);
  7.1170 +#endif
  7.1171 +        r->ebx = (r->ebx & ~0xffff) | cur_psp;
  7.1172 +        break;
  7.1173 +    case 0x55: /* create child PSP */
  7.1174 +        {
  7.1175 +            uint8_t *psp_ptr;
  7.1176 +#ifdef DUMP_INT21
  7.1177 +            printf("int21: create child PSP: psp=0x%04x last_seg=0x%04x\n", 
  7.1178 +                   (uint16_t)r->edx, (uint16_t)r->esi);
  7.1179 +#endif
  7.1180 +            psp_ptr = seg_to_linear(r->edx & 0xffff, 0);
  7.1181 +            memset(psp_ptr, 0, 0x80);
  7.1182 +            psp_ptr[0] = 0xcd; /* int $0x20 */
  7.1183 +            psp_ptr[1] = 0x20;
  7.1184 +            *(uint16_t *)(psp_ptr + 2) = r->esi;
  7.1185 +            r->eax = (r->eax & ~0xff);
  7.1186 +        }
  7.1187 +        break;
  7.1188 +    default:
  7.1189 +    unsupported:
  7.1190 +        unsupported_function(r, 0x21, ah);
  7.1191 +    }
  7.1192 +}
  7.1193 +    
  7.1194 +void do_int29(struct vm86_regs *r)
  7.1195 +{
  7.1196 +    uint8_t c = r->eax;
  7.1197 +    write(1, &c, 1);
  7.1198 +}
  7.1199 +
  7.1200 +void raise_interrupt(int number)
  7.1201 +{
  7.1202 +    if (* (uint32_t *) seg_to_linear(0, number * 4) == 0)
  7.1203 +        return;
  7.1204 +    // FIXME VM86_SIGNAL
  7.1205 +}
  7.1206 +
  7.1207 +void biosclock()
  7.1208 +{
  7.1209 +    uint32_t *timer = (uint32_t *) seg_to_linear(0, 0x46C);
  7.1210 +    ++*timer;
  7.1211 +    raise_interrupt(8);
  7.1212 +    raise_interrupt(0x1C);
  7.1213 +}
  7.1214 +
  7.1215 +int main(int argc, char **argv)
  7.1216 +{
  7.1217 +    uint8_t *vm86_mem;
  7.1218 +    const char *filename;
  7.1219 +    int ret;
  7.1220 +    uint32_t file_size;
  7.1221 +    struct sigaction sa; 
  7.1222 +    struct itimerval timerval;
  7.1223 +    struct vm86plus_struct ctx;
  7.1224 +    struct vm86_regs *r;
  7.1225 +    ExecParamBlock blk1, *blk = &blk1;
  7.1226 +
  7.1227 +    if (argc < 2)
  7.1228 +        usage();
  7.1229 +    filename = argv[1];
  7.1230 +
  7.1231 +    vm86_mem = mmap((void *)0x00000000, 0x110000,
  7.1232 +                    PROT_WRITE | PROT_READ | PROT_EXEC,
  7.1233 +                    MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0);
  7.1234 +    if (vm86_mem == MAP_FAILED) {
  7.1235 +        perror("mmap");
  7.1236 +        exit(1);
  7.1237 +    }
  7.1238 +
  7.1239 +    memset(&ctx, 0, sizeof(ctx));
  7.1240 +    r = &ctx.regs;
  7.1241 +    set_bit((uint8_t *)&ctx.int_revectored, 0x10);
  7.1242 +    set_bit((uint8_t *)&ctx.int_revectored, 0x13);
  7.1243 +    set_bit((uint8_t *)&ctx.int_revectored, 0x15);
  7.1244 +    set_bit((uint8_t *)&ctx.int_revectored, 0x16);
  7.1245 +    set_bit((uint8_t *)&ctx.int_revectored, 0x1a);
  7.1246 +    set_bit((uint8_t *)&ctx.int_revectored, 0x20);
  7.1247 +    set_bit((uint8_t *)&ctx.int_revectored, 0x21);
  7.1248 +    set_bit((uint8_t *)&ctx.int_revectored, 0x29);
  7.1249 +
  7.1250 +    dos_init();
  7.1251 +
  7.1252 +    if (strstr(filename,".com") || strstr(filename,".exe") ||
  7.1253 +        strstr(filename,".COM") || strstr(filename,".EXE")) {
  7.1254 +        ret = load_com(blk, filename, &file_size, argc, argv);
  7.1255 +        if (ret < 0) {
  7.1256 +            perror(filename);
  7.1257 +            exit(1);
  7.1258 +        }
  7.1259 +        cur_psp = ret;
  7.1260 +
  7.1261 +        /* init basic registers */
  7.1262 +        r->eip = blk->ip;
  7.1263 +        r->esp = blk->sp + 2; /* pop ax value */
  7.1264 +        r->cs = blk->cs;
  7.1265 +        r->ss = blk->ss;
  7.1266 +        r->ds = cur_psp;
  7.1267 +        r->es = cur_psp;
  7.1268 +        r->eflags = VIF_MASK;
  7.1269 +    
  7.1270 +        /* the value of these registers seem to be assumed by pi_10.com */
  7.1271 +        r->esi = 0x100;
  7.1272 +#if 0
  7.1273 +        r->ebx = file_size >> 16;
  7.1274 +        r->ecx = file_size & 0xffff;
  7.1275 +#else
  7.1276 +        r->ecx = 0xff;
  7.1277 +#endif
  7.1278 +        r->ebp = 0x0900;
  7.1279 +        r->edi = 0xfffe;
  7.1280 +    }
  7.1281 +    else {
  7.1282 +        if (load_boot(filename, r) < 0) {
  7.1283 +            if (errno)
  7.1284 +                perror(filename);
  7.1285 +            exit(1);
  7.1286 +        }
  7.1287 +    }
  7.1288 +
  7.1289 +    sa.sa_handler = biosclock;
  7.1290 +    sigemptyset(&sa.sa_mask);
  7.1291 +    sa.sa_flags = SA_RESTART;
  7.1292 +    if (sigaction(SIGALRM, &sa, 0) == 0) {
  7.1293 +        timerval.it_interval.tv_sec  = timerval.it_value.tv_sec  = 0;
  7.1294 +        timerval.it_interval.tv_usec = timerval.it_value.tv_usec = 10000000 / 182;
  7.1295 +        setitimer (ITIMER_REAL, &timerval, NULL);
  7.1296 +    }
  7.1297 +
  7.1298 +    for(;;) {
  7.1299 +        ret = vm86(VM86_ENTER, &ctx);
  7.1300 +        switch(VM86_TYPE(ret)) {
  7.1301 +        case VM86_INTx:
  7.1302 +            {
  7.1303 +                int int_num;
  7.1304 +
  7.1305 +                int_num = VM86_ARG(ret);
  7.1306 +                switch(int_num) {
  7.1307 +                case 0x10:
  7.1308 +                    do_int10(r);
  7.1309 +                    break;
  7.1310 +                case 0x13:
  7.1311 +                    do_int13(r);
  7.1312 +                    break;
  7.1313 +                case 0x15:
  7.1314 +                    do_int15(r);
  7.1315 +                    break;
  7.1316 +                case 0x16:
  7.1317 +                    do_int16(r);
  7.1318 +                    break;
  7.1319 +                case 0x1a:
  7.1320 +                    do_int1a(r);
  7.1321 +                    break;
  7.1322 +                case 0x20:
  7.1323 +                    do_int20(r);
  7.1324 +                    break;
  7.1325 +                case 0x21:
  7.1326 +                    do_int21(r);
  7.1327 +                    break;
  7.1328 +                case 0x29:
  7.1329 +                    do_int29(r);
  7.1330 +                    break;
  7.1331 +                default:
  7.1332 +                    fprintf(stderr, "unsupported int 0x%02x\n", int_num);
  7.1333 +                    dump_regs(&ctx.regs);
  7.1334 +                    break;
  7.1335 +                }
  7.1336 +            }
  7.1337 +            break;
  7.1338 +        case VM86_SIGNAL:
  7.1339 +            /* a signal came, we just ignore that */
  7.1340 +            break;
  7.1341 +        case VM86_STI:
  7.1342 +            break;
  7.1343 +        case VM86_TRAP:
  7.1344 +            /* just executes the interruption */
  7.1345 +            {
  7.1346 +                uint16_t *int_vector;
  7.1347 +                uint32_t eflags;
  7.1348 +                
  7.1349 +                eflags = r->eflags & ~IF_MASK;
  7.1350 +                if (r->eflags & VIF_MASK)
  7.1351 +                    eflags |= IF_MASK;
  7.1352 +                pushw(r, eflags);
  7.1353 +                pushw(r, r->cs);
  7.1354 +                pushw(r, r->eip);
  7.1355 +                int_vector = (uint16_t *)seg_to_linear(0, VM86_ARG(ret) * 4);
  7.1356 +                r->eip = int_vector[0];
  7.1357 +                r->cs = int_vector[1];
  7.1358 +                r->eflags &= ~(VIF_MASK | TF_MASK | AC_MASK);
  7.1359 +            }
  7.1360 +            break;
  7.1361 +        default:
  7.1362 +            fprintf(stderr, "unhandled vm86 return code (0x%x)\n", ret);
  7.1363 +            dump_regs(&ctx.regs);
  7.1364 +            exit(1);
  7.1365 +        }
  7.1366 +    }
  7.1367 +}