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 +}