New upstream version 2.0-0.9
Some checks failed
Build / build (push) Has been cancelled

This commit is contained in:
geos_one
2025-08-14 09:28:49 +02:00
parent c338ff82fb
commit 17bb5d7efa
634 changed files with 19105 additions and 52303 deletions

View File

@@ -5,7 +5,7 @@ import re
import traceback
import unittest
from datetime import datetime, timezone
from datetime import datetime
from hashlib import sha1
from os import environ, rename
from os.path import exists, join
@@ -16,7 +16,6 @@ from subprocess import (Popen, call, check_call, check_output,
DEVNULL, STDOUT, TimeoutExpired, CalledProcessError)
from sys import exit, stdout, stderr, version_info
from tarfile import open as topen
from time import sleep
from unittest.util import strclass
BINSDIR = "test-binaries"
@@ -33,25 +32,6 @@ VFAT_FIMAGE = "/img/dosemu.img"
VFAT_HELPER = "/bin/dosemu_fat_mount.sh"
VFAT_MNTPNT = "/mnt/dosemu"
TAP_HELPER = "/bin/dosemu_tap_interface.sh"
# Get any test binaries we need
TEST_BINARY_HOST = "http://www.spheresystems.co.uk/test-binaries"
TEST_BINARIES = (
'DR-DOS-7.01.tar',
'FR-DOS-1.20.tar',
'FR-DOS-1.30.tar',
'MS-DOS-6.22.tar',
'MS-DOS-7.00.tar',
'MS-DOS-7.10.tar',
'VARIOUS.tar',
'TEST_CRYNWR.tar',
'TEST_DOSLFN.tar',
'TEST_EMM286.tar',
'TEST_JAPHETH.tar',
'TEST_MTCP.tar',
)
def mkstring(length):
return ''.join(random.choice(string.hexdigits) for x in range(length))
@@ -75,7 +55,6 @@ def setup_vfat_mounted_image(self):
except (CalledProcessError, TimeoutExpired):
self.skipTest("mount helper ineffective")
def teardown_vfat_mounted_image(self):
if not exists(VFAT_HELPER):
self.skipTest("mount helper not installed")
@@ -83,41 +62,8 @@ def teardown_vfat_mounted_image(self):
check_call(["sudo", VFAT_HELPER, "umount"], stderr=STDOUT)
def setup_tap_interface(self):
if not exists(TAP_HELPER):
self.skipTest("tap interface helper not installed")
check_call(["sudo", TAP_HELPER, "setup"], stderr=STDOUT)
def teardown_tap_interface(self):
if not exists(TAP_HELPER):
self.skipTest("tap interface helper not installed")
check_call(["sudo", TAP_HELPER, "teardown"], stderr=STDOUT)
def get_test_binaries():
tbindir = Path('.').resolve() / BINSDIR
if tbindir.is_symlink():
tbindir = tbindir.resolve()
if not tbindir.exists():
tbindir.mkdir()
for tfile in TEST_BINARIES:
if not Path(tbindir / tfile).exists():
check_call([
"wget",
"--no-verbose",
TEST_BINARY_HOST + '/' + tfile,
], stderr=STDOUT, cwd=tbindir)
class BaseTestCase(object):
attrs = []
@classmethod
def setUpClass(cls):
cls.topdir = Path('.').resolve()
@@ -154,26 +100,21 @@ class BaseTestCase(object):
if cls.tarfile is None:
cls.tarfile = cls.prettyname + ".tar"
if cls.tarfile != "":
if cls.tarfile not in TEST_BINARIES:
exit("\nUpdate tuple TEST_BINARIES for '%s'\n" % cls.prettyname)
if not exists(join(BINSDIR, cls.tarfile)):
exit("\nMissing test binary file, please run test/test_dos.py --get-test-binaries\n")
if cls.tarfile != "" and not exists(join(BINSDIR, cls.tarfile)):
raise unittest.SkipTest(
"TestCase %s binary not available" % cls.prettyname)
@classmethod
def tearDownClass(cls):
pass
def setUp(self):
# Process and skip actions
for key, value in self.actions.items():
if re.match(key, self._testMethodName):
d = {
SKIP: "",
KNOWNFAIL: "known failure",
UNSUPPORTED: "unsupported",
}
self.skipTest(d.get(value, "unknown key"))
if self.actions.get(self._testMethodName) == SKIP:
self.skipTest("")
elif self.actions.get(self._testMethodName) == KNOWNFAIL:
self.skipTest("known failure")
elif self.actions.get(self._testMethodName) == UNSUPPORTED:
self.skipTest("unsupported")
for p in self.imagedir.iterdir():
if p.is_dir():
@@ -189,7 +130,7 @@ class BaseTestCase(object):
self.unTarOrSkip(self.tarfile, self.files)
# Empty dosemu.conf for default values
self.mkfile("dosemu.conf", """\n""", self.imagedir)
self.mkfile("dosemu.conf", """$_force_fs_redirect = (off)\n""", self.imagedir)
# Create startup files
self.setUpDosAutoexec()
@@ -223,8 +164,26 @@ class BaseTestCase(object):
# helpers
def utcnow(self):
return datetime.now(timezone.utc)
def mkcom_with_gas(self, fname, content, dname=None):
if dname is None:
p = self.workdir
else:
p = Path(dname).resolve()
basename = str(p / fname)
with open(basename + ".S", "w") as f:
f.write(content)
check_call(["as", "-o", basename + ".o", basename + ".S"])
check_call(["gcc",
"-static",
"-Wl,--section-start=.text=0x100,-e,_start16", "-nostdlib",
"-o", basename + ".com.elf",
basename + ".o"])
check_call(["objcopy",
"-j", ".text", "-O", "binary",
basename + ".com.elf",
basename + ".com"])
check_call(["rm", basename + ".o", basename + ".com.elf"])
def mkcom_with_ia16(self, fname, content, dname=None):
if dname is None:
@@ -235,7 +194,7 @@ class BaseTestCase(object):
with open(basename + ".c", "w") as f:
f.write(content)
check_call(["ia16-elf-gcc", "-mcmodel=tiny",
check_call(["ia16-elf-gcc", "-mcmodel=small",
"-o", basename + ".com", basename + ".c", "-li86"])
def mkexe_with_djgpp(self, fname, content, dname=None):
@@ -250,18 +209,6 @@ class BaseTestCase(object):
check_call(["i586-pc-msdosdjgpp-gcc",
"-o", basename + ".exe", basename + ".c"])
def mkcom_with_nasm(self, fname, content, dname=None):
if dname is None:
p = self.workdir
else:
p = Path(dname).resolve()
basename = p / fname
sfile = basename.with_suffix('.asm')
sfile.write_text(content)
ofile = basename.with_suffix('.com')
check_call(["nasm", "-f", "bin", "-o", str(ofile), str(sfile)])
def mkfile(self, fname, content, dname=None, mode="w", newline=None):
if dname is None:
p = self.workdir / fname
@@ -367,44 +314,6 @@ class BaseTestCase(object):
return name
def mkimage_vbr(self, fat, lfn=False, cwd=None):
if fat == "12":
bcount = 306 * 4 * 17 # type 1
elif fat == "16":
bcount = 615 * 4 * 17 # type 2
elif fat == "16b":
bcount = 900 * 15 * 17 # type 9
elif fat == "32":
bcount = 1048576 # 1 GiB
else:
raise ValueError
name = "fat%s.img" % fat
# mkfs.fat [OPTIONS] DEVICE [BLOCK-COUNT]
check_call(
["mkfs",
"-t", ("fat", "vfat")[lfn],
"-C",
"-F", fat[0:2],
str(self.imagedir / name),
str(bcount)],
stdout=DEVNULL, stderr=DEVNULL)
if cwd is None:
cwd = self.workdir
# mcopy -i ../fat32.img -s -v * ::/
srcs = [str(f) for f in cwd.glob('*')]
if srcs: # copy files
args = ["mcopy",
"-i", str(self.imagedir / name),
"-s"]
args += srcs
args += ["::/",]
check_call(args, cwd=cwd, stdout=DEVNULL, stderr=DEVNULL)
return name
def patch(self, fname, changes, cwd=None):
if cwd is None:
cwd = self.workdir
@@ -423,7 +332,7 @@ class BaseTestCase(object):
f.write(c[2])
def runDosemu(self, cmd, opts=None, outfile=None, config=None, timeout=5,
eofisok=False, interactions=[]):
interactions=[]):
# Note: if debugging is turned on then times increase 10x
dbin = "bin/dosemu"
args = ["-f", str(self.imagedir / "dosemu.conf"),
@@ -453,10 +362,7 @@ class BaseTestCase(object):
child.send(resp[1])
if outfile is None:
ret += child.before.decode('ASCII', 'replace')
trms = ['rem end',]
if eofisok:
trms += [pexpect.EOF,]
child.expect(trms, timeout=timeout)
child.expect(['rem end'], timeout=timeout)
if outfile is None:
ret += child.before.decode('ASCII', 'replace')
else:
@@ -464,10 +370,6 @@ class BaseTestCase(object):
ret = f.read()
except pexpect.TIMEOUT:
ret = 'Timeout'
tlog = self.logfiles['log'][0].read_text()
if '(gdb) Attaching to program' in tlog:
sleep(60)
self.shouldStop = True
except pexpect.EOF:
ret = 'EndOfFile'
@@ -491,18 +393,14 @@ class BaseTestCase(object):
if config is not None:
self.mkfile("dosemu.conf", config, dname=self.imagedir, mode="a")
self.logfiles['xpt'][1] = "output.log"
try:
ret = check_output(args, cwd=cwd, timeout=timeout, stderr=STDOUT).decode('ASCII')
self.logfiles['xpt'][0].write_text(ret)
except CalledProcessError as e:
ret = e.output.decode('ASCII')
ret += '\nNonZeroReturn:%d\n' % e.returncode
self.logfiles['xpt'][0].write_text(ret)
ret = check_output(args, cwd=cwd, timeout=timeout, stderr=STDOUT)
with open(self.logfiles['xpt'][0], "w") as f:
f.write(ret.decode('ASCII'))
except TimeoutExpired as e:
ret = e.output.decode('ASCII')
ret += '\nTimeout:%d seconds\n' % timeout
self.logfiles['xpt'][0].write_text(ret)
ret = 'Timeout'
with open(self.logfiles['xpt'][0], "w") as f:
f.write(e.output.decode('ASCII'))
return ret
@@ -516,7 +414,7 @@ class MyTestResult(unittest.TextTestResult):
def startTest(self, test):
super(MyTestResult, self).startTest(test)
self.starttime = test.utcnow()
self.starttime = datetime.utcnow()
name = test.id().replace('__main__', test.pname)
test.logfiles = {
@@ -526,15 +424,14 @@ class MyTestResult(unittest.TextTestResult):
test.firstsub = True
test.msg = None
def _is_relevant_tb_level(self, tb):
return '__unittest' in tb.tb_frame.f_globals
def _count_relevant_tb_levels(self, tb):
length = 0
while tb and not self._is_relevant_tb_level(tb):
length += 1
tb = tb.tb_next
return length
def addFailure(self, test, err):
if self.showAll:
self.stream.writeln("FAIL")
elif self.dots:
self.stream.write('F')
self.stream.flush()
self.failures.append((test, self.gather_info_for_failure(err, test)))
self._mirrorOutput = True
def gather_info_for_failure(self, err, test):
"""Gather traceback, stdout, stderr, dosemu and expect logs"""
@@ -592,22 +489,11 @@ class MyTestResult(unittest.TextTestResult):
return ''.join(msgLines)
def addFailure(self, test, err):
if self.showAll:
self.stream.writeln("FAIL")
elif self.dots:
self.stream.write('F')
self.stream.flush()
self.failures.append((test, self.gather_info_for_failure(err, test)))
self._mirrorOutput = True
if getattr(test, 'shouldStop', None) is not None:
self.shouldStop = test.shouldStop
def addSuccess(self, test):
super(unittest.TextTestResult, self).addSuccess(test)
if self.showAll:
if self.starttime is not None:
duration = test.utcnow() - self.starttime
duration = datetime.utcnow() - self.starttime
msg = (" " + test.msg) if test.msg else ""
self.stream.writeln("ok ({:>6.2f}s){}".format(duration.total_seconds(), msg))
else:

View File

@@ -1,29 +1,15 @@
include ../../Makefile.conf
#CC=clang -fno-integrated-as -fverbose-asm
CC=gcc
CFLAGS=-Wall -O2 -g -fno-strict-aliasing -fno-pic -fno-pie -no-pie
DJGPP = i586-pc-msdosdjgpp-gcc
DJFLAGS=-Wall -O2 -g -gdwarf-2 -fno-strict-aliasing -fno-pic -fno-pie -no-pie
# Force CC to gcc, as clang compiled binary segfaults
CC = gcc
CFLAGS := $(DJFLAGS)
ifeq ($(CC), clang)
CFLAGS += -fno-integrated-as -fverbose-asm
endif
LDFLAGS=
SOURCES = test-i386.c test-i386-code16.S test-i386-vm86.S
ALL_SRC = $(SOURCES) $(wildcard *.h)
all: dosbin.exe
reffile.log: native32
./native32 --common-tests > $@
all: dosbin.exe native32 native64
# i386/x86_64 emulation test (test various opcodes) */
dosbin.exe: $(ALL_SRC)
$(DJGPP) $(DJFLAGS) $(LDFLAGS) -o $@ $(SOURCES) -lm
$(DJGPP) $(CFLAGS) $(LDFLAGS) -o $@ $(SOURCES) -lm
native32: $(ALL_SRC)
$(CC) -m32 $(CFLAGS) $(LDFLAGS) -o $@ $(SOURCES) -lm

File diff suppressed because it is too large Load Diff

View File

@@ -77,7 +77,3 @@ myfunc2:
code16_end:
#ifdef __ELF__
.section .note.GNU-stack,"",%progbits
#endif

View File

@@ -1,3 +1,4 @@
#define exec_op glue(exec_, OP)
#define exec_opq glue(glue(exec_, OP), q)
#define exec_opl glue(glue(exec_, OP), l)
@@ -57,10 +58,6 @@ void exec_opl(long s2, long s0, long s1, long iflags)
void exec_opw(long s2, long s0, long s1, long iflags)
{
long res, flags;
if ((strcmp(stringify(OP), "shld") == 0 ||
strcmp(stringify(OP), "shrd") == 0) && s1 > 16)
return;
res = s0;
flags = iflags;
EXECSHIFT("w", "w", res, s1, s2, flags);
@@ -112,10 +109,6 @@ void exec_opl(long s2, long s0, long s1, long iflags)
void exec_opw(long s2, long s0, long s1, long iflags)
{
long res, flags;
if ((strcmp(stringify(OP), "shld") == 0 ||
strcmp(stringify(OP), "shrd") == 0) && s1 > 16)
return;
res = s0;
flags = iflags;
EXECSHIFT("w", "w", res, s1, s2, flags);
@@ -151,7 +144,11 @@ void exec_op(long s2, long s0, long s1)
exec_opq(s2, s0, s1, 0);
#endif
exec_opl(s2, s0, s1, 0);
#ifdef OP_SHIFTD
exec_opw(s2, s0, s1, 0);
#else
exec_opw(s2, s0, s1, 0);
#endif
#ifndef OP_NOBYTE
exec_opb(s0, s1, 0);
#endif

View File

@@ -105,7 +105,3 @@ IF_msg1:
.string "If you see a diff here, your Linux kernel is buggy, please update to 2.4.20 kernel\n$"
vm86_code_end:
#ifdef __ELF__
.section .note.GNU-stack,"",%progbits
#endif

View File

@@ -2416,8 +2416,8 @@ static void test_enter(void)
#ifdef TEST_SSE
typedef int __m64 __attribute__ ((vector_size (8)));
typedef float __m128 __attribute__ ((vector_size (16)));
typedef int __m64 __attribute__ ((__mode__ (__V2SI__)));
typedef float __m128 __attribute__ ((__mode__(__V4SF__)));
typedef union {
double d[2];
@@ -2591,7 +2591,7 @@ void test_sse_comi(double a1, double b1)
}
/* Force %xmm0 usage to avoid the case where both register index are 0
to test instruction decoding more extensively */
to test intruction decoding more extensively */
#define CVT_OP_XMM2MMX(op)\
{\
asm volatile (#op " %1, %0" : "=y" (r.q[0]) : "x" (a.dq) \
@@ -3084,7 +3084,7 @@ int main(int argc, char **argv)
if (argc >= 2 && strcmp(argv[1], "--common-tests") == 0)
return 0;
// tests that will probably never produce the same output on different platforms
// tests that will probabaly never produce the same output on different platforms
test_exceptions();
test_enter();

View File

@@ -1,27 +0,0 @@
#!/bin/sh
# Notes:
# 1/ this file needs to be installed in the well known location by root
# cp test/dosemu_tap_interface.sh /bin/.
# chmod 755 /bin/dosemu_tap_interface.sh
# chown root.root /bin/dosemu_tap_interface.sh
#
# 2/ sudo needs to be configured by root for the test user to run it
# without passwd
# echo 'ajb ALL=(ALL) NOPASSWD: /bin/dosemu_tap_interface.sh' > /etc/sudoers.d/dosemu
# chmod 0440 /etc/sudoers.d/dosemu
if [ "$1" = "setup" ] ; then
ip tuntap add mode tap user ${SUDO_UID} tap0
brctl addif virbr0 tap0
ifconfig tap0 promisc up
elif [ "$1" = "teardown" ] ; then
ifconfig tap0 down
brctl delif virbr0 tap0
ip tuntap del mode tap tap0
else
echo "${0}: incorrect args"
exit 1
fi

View File

@@ -1,5 +1,5 @@
all: dpmialoc.com dpmimini.com dpmims.com dpmipsp.com
all: dpmialoc.com dpmimini.com dpmims.com dpmipsp.com
%.com: %.asm
nasm -f bin -I../lmacros/ -o $@ $<

View File

@@ -1,5 +1,3 @@
import re
from cpuinfo import get_cpu_info
from os import access, R_OK, W_OK
@@ -9,7 +7,7 @@ def cpu_trap_flag(self, cpu_vm):
raise ValueError('invalid argument')
if cpu_vm == "kvm" and not access("/dev/kvm", W_OK|R_OK):
self.skipTest("requires KVM")
self.skipTest("No KVM available")
config = """
$_hdimage = "dXXXXs/c:hdtype1 +1"
@@ -23,80 +21,57 @@ rem end
""", newline="\r\n")
# compile sources
self.mkcom_with_nasm("cputrapf", r"""
self.mkcom_with_gas("cputrapf", r"""
.text
.code16
bits 16
cpu 386
.globl _start16
_start16:
org 100h
push %cs
pop %ds
section .text
push cs
pop ds
mov ax, 2501h
mov dx, int1
int 21h
mov ax, 14h
mov bx, 1
int 0xe6
push 3003h
push 3303h
popf
popf
movw $0x2501, %ax
movw $int1, %dx
int $0x21
pushw $0x3003
pushw $0x3303
popfw
popfw
nop
mov ax, 14h
mov bx, 0
int 0xe6
mov ah, 9 ; print string
mov dx, result
int 21h
movb $0x9, %ah # print string
movw $result, %dx
int $0x21
exit:
mov ax, 4c00h
int 21h
movw $0x4c00, %ax
int $0x21
ret
int1:
inc byte [cs:result.cnt]
incb %cs:cnt
iret
section .data
result:
db "Result is ("
.cnt:
db '0'
db ')',13,10,'$'
.ascii "Result is ("
cnt:
.byte '0'
.ascii ")\r\n$"
""")
results = self.runDosemu("testit.bat", config=config)
# Extract the result value
r1 = re.compile(r'Result is \((\d+)\)')
self.assertRegex(results, r1)
t = r1.search(results)
rval = int(t.group(1), 10)
# Some unknown error in the test
self.assertNotEqual(rval, 0, results)
self.assertIn("Result is (1)", results)
if cpu_vm != 'kvm':
self.assertEqual(rval, 1, results)
return
# check for fixup
fixupmsg = "KVM: not applying TF fixup"
fixupmsg = "KVM: applying TF fixup"
knownbad = (
'AMD FX(tm)-8350 Eight-Core Processor',
'AMD A10-7870K Radeon R7, 12 Compute Cores 4C+8G',
'AMD Ryzen 5 5600U with Radeon Graphics',
'AMD EPYC 7763 64-Core Processor',
)
# get log content
@@ -113,11 +88,11 @@ result:
except KeyError:
name = str(cpu)
if rval == 1:
if name in knownbad:
self.fail("Unexpected success with cpu '%s'" % name)
elif rval > 1 or fixupmsg in results or fixupmsg in logcontents:
if name in knownbad:
if name in knownbad:
if fixupmsg in results or fixupmsg in logcontents:
self.setMessage("known bad cpu '%s'" % name)
else:
self.fail("Unexpected success with cpu '%s'" % name)
else:
if fixupmsg in results or fixupmsg in logcontents:
self.fail("Fail with unknown cpu '%s'" % name)

View File

@@ -30,169 +30,166 @@ rem end
""" % ename, newline="\r\n")
# compile sources
self.mkcom_with_nasm(ename, r"""
bits 16
cpu 386
self.mkcom_with_gas(ename, r"""
.text
.code16
org 100h
.globl _start16
_start16:
section .text
push %%cs
pop %%ds
push cs
pop ds
mov ax, 3c00h ; create file
mov cx, 0
mov dx, fname
int 21h
movw $0x3c00, %%ax # create file
movw $0, %%cx
movw $fname, %%dx
int $0x21
jc prfailcreate
mov word [fhndl], ax
movw %%ax, fhndl
mov ax, 4000h ; write testdata
mov bx, word [fhndl]
mov cx, fdatalen
mov dx, fdata
int 21h
movw $0x4000, %%ax # write testdata
movw fhndl, %%bx
movw $fdatalen, %%cx
movw $fdata, %%dx
int $0x21
jc prfailwrite
cmp ax, fdatalen
cmpw $fdatalen, %%ax
jne prnumwrite
mov ax, 3e00h ; close file
mov bx, word [fhndl]
int 21h
movw $0x3e00, %%ax # close file
movw fhndl, %%bx
int $0x21
mov ax, 3d00h ; open file readonly
mov dx, fname
int 21h
movw $0x3d00, %%ax # open file readonly
movw $fname, %%dx
int $0x21
jc prfailopen
mov word [fhndl], ax
movw %%ax, fhndl
mov ax, 3f00h ; read from file to middle
mov bx, word [fhndl]
mov cx, 16
mov dx, ftemp
int 21h
movw $0x3f00, %%ax # read from file to middle
movw fhndl, %%bx
movw $16, %%cx
movw $ftemp, %%dx
int $0x21
jc prfailread
cmp ax, 16
cmpw $16, %%ax
jne prnumread
mov ax, %xh ; seek from whence to somewhere
mov bx, word [fhndl]
mov si, seekval
mov cx, [ds:si + 2]
mov dx, [ds:si]
int 21h
movw $0x%x, %%ax # seek from whence to somewhere
movw fhndl, %%bx
movw $seekval, %%si
movw %%ds:2(%%si), %%cx
movw %%ds:0(%%si), %%dx
int $0x21
jc prcarryset
mov ax, 3f00h ; read 4 chars from new position
mov bx, word [fhndl]
mov cx, 4
mov dx, fdata2
int 21h
movw $0x3f00, %%ax # read 4 chars from new position
movw fhndl, %%bx
movw $4, %%cx
movw $fdata2, %%dx
int $0x21
jc prfailread2
cmp ax, 4
cmpw $4, %%ax
jne prnumread2
jmp prsucc
prfailcreate:
mov dx, failcreate
jmp @1
movw $failcreate, %%dx
jmp 1f
prfailwrite:
mov dx, failwrite
jmp @2
movw $failwrite, %%dx
jmp 2f
prnumwrite:
mov dx, numwrite
jmp @2
movw $numwrite, %%dx
jmp 2f
prfailopen:
mov dx, failopen
jmp @1
movw $failopen, %%dx
jmp 1f
prfailread:
mov dx, failread
jmp @2
movw $failread, %%dx
jmp 2f
prnumread:
mov dx, numread
jmp @2
movw $numread, %%dx
jmp 2f
prcarryset:
mov dx, carryset
jmp @2
movw $carryset, %%dx
jmp 2f
prfailread2:
mov dx, failread2
jmp @2
movw $failread2, %%dx
jmp 2f
prnumread2:
mov dx, numread2
jmp @2
movw $numread2, %%dx
jmp 2f
prsucc:
mov byte [fdata2 + 4], ')'
mov byte [fdata2 + 5], 13
mov byte [fdata2 + 6], 10
mov byte [fdata2 + 7], '$'
mov dx, success
jmp @2
movb $')', (fdata2 + 4)
movb $'\r', (fdata2 + 5)
movb $'\n', (fdata2 + 6)
movb $'$', (fdata2 + 7)
movw $success, %%dx
jmp 2f
@2:
mov ax, 3e00h ; close file
mov bx, word [fhndl]
int 21h
2:
movw $0x3e00, %%ax # close file
movw fhndl, %%bx
int $0x21
@1:
mov ah, 9 ; print string
int 21h
1:
movb $0x9, %%ah # print string
int $0x21
exit:
mov ah, 4ch
int 21h
section .data
movb $0x4c, %%ah
int $0x21
seekval:
dd %d
.long %d
fname:
db "%s", 0
.asciz "%s"
fhndl:
dw 0
.word 0
fdata:
db "%s"
fdatalen equ $ - fdata
.ascii "%s"
fdatalen = (. - fdata)
success:
db "Operation Success("
.ascii "Operation Success("
fdata2:
times 64 db 0
.space 64
ftemp:
times 64 db 0
.space 64
failcreate:
db "Create Operation Failed",13,10,'$'
.ascii "Create Operation Failed\r\n$"
failwrite:
db "Write Operation Failed",13,10,'$'
.ascii "Write Operation Failed\r\n$"
numwrite:
db "Write Incorrect Length",13,10,'$'
.ascii "Write Incorrect Length\r\n$"
failopen:
db "Open Operation Failed",13,10,'$'
.ascii "Open Operation Failed\r\n$"
failread:
db "Read Operation Failed",13,10,'$'
.ascii "Read Operation Failed\r\n$"
numread:
db "Read Not 16 Chars",13,10,'$'
.ascii "Read Not 16 Chars\r\n$"
carryset:
db "Seek Carry Set",13,10,'$'
.ascii "Seek Carry Set\r\n$"
failread2:
db "Read2 Operation Failed",13,10,'$'
.ascii "Read2 Operation Failed\r\n$"
numread2:
db "Read2 Not 4 Chars",13,10,'$'
.ascii "Read2 Not 4 Chars\r\n$"
""" % (dosfunc, seekval, "test.fil", testdata))

View File

@@ -29,138 +29,135 @@ rem end
}[testfunc]
# compile sources
self.mkcom_with_nasm(ename, r"""
bits 16
cpu 386
self.mkcom_with_gas(ename, r"""
.text
.code16
org 100h
.globl _start16
_start16:
section .text
push %%cs
pop %%ds
push cs
pop ds
mov ax, 3c00h ; create file
mov cx, 0
mov dx, fname
int 21h
movw $0x3c00, %%ax # create file
movw $0, %%cx
movw $fname, %%dx
int $0x21
jc prfailcreate
mov word [fhndl], ax
movw %%ax, fhndl
mov cx, 1000h ; number of 512 byte chunks
movw $0x1000, %%cx # number of 512 byte chunks
@1:
push cx
mov ax, 4000h ; write testdata
mov bx, word [fhndl]
mov cx, fdatalen
mov dx, fdata
int 21h
pop cx
1:
pushw %%cx
movw $0x4000, %%ax # write testdata
movw fhndl, %%bx
movw $fdatalen, %%cx
movw $fdata, %%dx
int $0x21
popw %%cx
jc prfailwrite
cmp ax, fdatalen
cmpw $fdatalen, %%ax
jne prnumwrite
loop @1
loop 1b
mov ax, %xh ; seek from whence to somewhere
mov bx, word [fhndl]
mov si, seekval
mov cx, word [ds:si + 2]
mov dx, word [ds:si]
int 21h
movw $0x%x, %%ax # seek from whence to somewhere
movw fhndl, %%bx
movw $seekval, %%si
movw %%ds:2(%%si), %%cx
movw %%ds:0(%%si), %%dx
int $0x21
jc prcarryset
shl edx, 16 ; compare the resultant position
mov dx, ax
mov ecx, long [expected]
cmp ecx, edx
shll $16, %%edx # compare the resultant position
movw %%ax, %%dx
movl expected, %%ecx
cmpl %%edx, %%ecx
jne prfailcompare
jmp prsucc
prfailcreate:
mov dx, failcreate
jmp @3
movw $failcreate, %%dx
jmp 1f
prfailwrite:
mov dx, failwrite
jmp @2
movw $failwrite, %%dx
jmp 2f
prnumwrite:
mov dx, numwrite
jmp @2
movw $numwrite, %%dx
jmp 2f
prcarryset:
mov dx, carryset
jmp @2
movw $carryset, %%dx
jmp 2f
prfailcompare:
mov dx, failcompare
jmp @2
movw $failcompare, %%dx
jmp 2f
prsucc:
mov dx, success
jmp @2
movw $success, %%dx
jmp 2f
@2:
mov ax, 3e00h ; close file
mov bx, word [fhndl]
int 21h
2:
movw $0x3e00, %%ax # close file
movw fhndl, %%bx
int $0x21
@3:
mov ah, 9 ; print string
int 21h
1:
movb $0x9, %%ah # print string
int $0x21
exit:
mov ah, 4ch
int 21h
section .data
movb $0x4c, %%ah
int $0x21
seekval:
dd %d
.long %d
expected:
dd %d
.long %d
fname:
db "test.fil", 0
.asciz "test.fil"
fhndl:
dw 0
.word 0
fdata:
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
db "0123456789abcdefFEDCBA9876543210"
fdatalen equ $ - fdata
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
.ascii "0123456789abcdefFEDCBA9876543210"
fdatalen = (. - fdata)
success:
db "Operation Success",13,10,'$'
.ascii "Operation Success\r\n$"
failcreate:
db "Create Operation Failed",13,10,'$'
.ascii "Create Operation Failed\r\n$"
failwrite:
db "Write Operation Failed",13,10,'$'
.ascii "Write Operation Failed\r\n$"
numwrite:
db "Write Incorrect Length",13,10,'$'
.ascii "Write Incorrect Length\r\n$"
carryset:
db "Seek Carry Set",13,10,'$'
.ascii "Seek Carry Set\r\n$"
failcompare:
db "File Position Incorrect",13,10,'$'
.ascii "File Position Incorrect\r\n$"
""" % (dosfunc, seekval, expected))

View File

@@ -31,7 +31,7 @@ void __far __interrupt (*oldint24)(void);
volatile uint16_t int24_ax;
void __far __interrupt __attribute__ ((near_section)) myint24(void); /* Prototype */
void __far __interrupt myint24(void); /* Prototype */
__asm (
"myint24:\n"
" pushw %bp\n"

View File

@@ -21,7 +21,7 @@ rem end
#include <unistd.h>
#define FNAME "FOO.DAT"
#define FDATA "0123456789abcdefghij"
#define FDATA "0123456789abc"
#define FDAT2 " 567 "
int main(int argc, char *argv[]) {
@@ -29,7 +29,6 @@ int main(int argc, char *argv[]) {
int ret, rc;
unsigned int attr;
char buf[80];
int read_allowed = 0;
if (_dos_creatnew(FNAME, 0, &hnd1) != 0) {
printf("FAIL: File '%s' not created\n", FNAME);
@@ -91,9 +90,12 @@ int main(int argc, char *argv[]) {
ret = _dos_lock(hnd2, 5, 3); // try the same lock handle 2
if (ret == 0) {
// extension, multiple read locks are allowed, make sure also read() works
printf("OKAY: Managed to lock again on file '%s' via different handle\n", FNAME);
read_allowed = 1;
printf("FAIL: Managed to lock again on file '%s' via different handle\n", FNAME);
_dos_unlock(hnd2, 5, 3);
_dos_close(hnd2);
_dos_unlock(hnd1, 5, 3);
_dos_close(hnd1);
return -1;
} else if (ret != 33) { // Should be lock violation
printf("FAIL: Refused second lock on file '%s' but return (err=%d != 33)\n", FNAME, ret);
_dos_close(hnd2);
@@ -104,31 +106,9 @@ int main(int argc, char *argv[]) {
printf("OKAY: Refused second lock on file '%s', err=%d\n", FNAME, ret);
}
/* lock adjacent region, should succeed */
ret = _dos_lock(hnd2, 8, 3);
if (ret == 0) {
printf("OKAY: Locked adjacent on file '%s' via different handle\n", FNAME);
} else {
printf("FAIL: Refused adjacent lock on file '%s' but return (err=%d != 33)\n", FNAME, ret);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
}
/* lock another region, should succeed */
ret = _dos_lock(hnd2, 14, 3);
if (ret == 0) {
printf("OKAY: Locked another reg on file '%s' via different handle\n", FNAME);
} else {
printf("FAIL: Refused another lock on file '%s' but return (err=%d != 33)\n", FNAME, ret);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
}
// try to read the locked region via the second handle (should succeed)
memset(buf, ' ', strlen(FDATA));
// try to read the locked region via the second handle
if (llseek(hnd2, 5, SEEK_SET) != 5) {
printf("FAIL: File '%s' seek failed\n", FNAME);
_dos_close(hnd2);
@@ -138,148 +118,13 @@ int main(int argc, char *argv[]) {
}
ret = _dos_read(hnd2, buf + 5, 3, &rc); // exact match conflict
if (ret == 0) {
if (!read_allowed) {
printf("FAIL: Read other's-locked data from file '%s' via second descriptor, cnt=%d\n", FNAME, rc);
_dos_close(hnd2);
_dos_unlock(hnd1, 5, 3);
_dos_close(hnd1);
return -1;
} else {
printf("OKAY: Read other's-locked data from file '%s' via second descriptor, cnt=%d\n", FNAME, rc);
}
} else {
if (!read_allowed) {
printf("OKAY: Refused to read others-locked data from file '%s' via second descriptor, err = %d\n", FNAME, ret);
} else {
printf("FAIL: Refused to read other's-locked data from file '%s' via second descriptor, err = %d\n", FNAME, ret);
_dos_close(hnd2);
_dos_unlock(hnd1, 5, 3);
_dos_close(hnd1);
return -1;
}
}
// try to read the locked region in the middle
if (llseek(hnd2, 6, SEEK_SET) != 6) {
printf("FAIL: File '%s' seek failed\n", FNAME);
printf("FAIL: Read locked data from file '%s' via second descriptor, cnt=%d\n", FNAME, rc);
_dos_close(hnd2);
_dos_unlock(hnd1, 5, 3);
_dos_close(hnd1);
return -1;
}
ret = _dos_read(hnd2, buf + 6, 1, &rc);
if (ret == 0) {
if (!read_allowed) {
printf("FAIL: Read within other's-locked data from file '%s' via second descriptor, cnt=%d\n", FNAME, rc);
_dos_close(hnd2);
_dos_unlock(hnd1, 5, 3);
_dos_close(hnd1);
return -1;
} else {
printf("OKAY: Read within other's-locked data from file '%s' via second descriptor, cnt=%d\n", FNAME, rc);
}
} else {
if (!read_allowed) {
printf("OKAY: Refused to read within other's-locked data from file '%s' via second descriptor, err = %d\n", FNAME, ret);
} else {
printf("FAIL: Refused to read within other's-locked data from file '%s' via second descriptor, err = %d\n", FNAME, ret);
_dos_close(hnd2);
_dos_unlock(hnd1, 5, 3);
_dos_close(hnd1);
return -1;
}
}
/* read multiple locked regions */
if (llseek(hnd2, 0, SEEK_SET) != 0) {
printf("FAIL: File '%s' seek failed\n", FNAME);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
}
ret = _dos_read(hnd2, buf, 20, &rc);
if (ret == 0) {
if (read_allowed) {
printf("OKAY: Read multiple locked data from file '%s' via second descriptor, cnt=%d\n", FNAME, rc);
} else {
printf("FAIL: Managed to read multiple locked regs from file '%s' via second descriptor, len = %d\n", FNAME, rc);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
}
} else {
if (read_allowed) {
printf("FAIL: Refused to read multiple locked regs from file '%s' via second descriptor, err = %d\n", FNAME, ret);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
} else {
printf("OKAY: Refused to read multiple locked regs from file '%s' via second descriptor, err = %d\n", FNAME, ret);
}
}
/* read multiple own-locked regions */
if (llseek(hnd2, 8, SEEK_SET) != 8) {
printf("FAIL: File '%s' seek failed\n", FNAME);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
}
ret = _dos_read(hnd2, buf + 8, 12, &rc);
if (ret == 0) {
printf("OKAY: Read multiple own-locked data from file '%s' via second descriptor, cnt=%d\n", FNAME, rc);
} else {
printf("FAIL: Refused to read multiple own-locked regs from file '%s' via second descriptor, err = %d\n", FNAME, ret);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
}
/* read from the middle of region */
if (llseek(hnd2, 9, SEEK_SET) != 9) {
printf("FAIL: File '%s' seek failed\n", FNAME);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
}
ret = _dos_read(hnd2, buf + 9, 11, &rc);
if (ret == 0) {
printf("OKAY: Read from middle own-locked reg from file '%s' via second descriptor, cnt=%d\n", FNAME, rc);
} else {
printf("FAIL: Refused to read from middle own-locked reg from file '%s' via second descriptor, err = %d\n", FNAME, ret);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
}
/* read from unlocked space and span the region */
if (llseek(hnd2, 13, SEEK_SET) != 13) {
printf("FAIL: File '%s' seek failed\n", FNAME);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
}
ret = _dos_read(hnd2, buf + 13, 7, &rc);
if (ret == 0) {
printf("OKAY: Read span own-locked reg from file '%s' via second descriptor, cnt=%d\n", FNAME, rc);
} else {
printf("FAIL: Refused to read span own-locked reg from file '%s' via second descriptor, err = %d\n", FNAME, ret);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
}
/* read within the locked region */
if (llseek(hnd2, 15, SEEK_SET) != 15) {
printf("FAIL: File '%s' seek failed\n", FNAME);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
}
ret = _dos_read(hnd2, buf + 15, 1, &rc);
if (ret == 0) {
printf("OKAY: Read within own-locked reg from file '%s' via second descriptor, cnt=%d\n", FNAME, rc);
} else {
printf("FAIL: Refused to read within own-locked reg from file '%s' via second descriptor, err = %d\n", FNAME, ret);
_dos_close(hnd2);
_dos_close(hnd1);
return -1;
printf("OKAY: Refused to read locked data from file '%s' via second descriptor, err = %d\n", FNAME, ret);
}
printf("PASS: all tests okay on file '%s'\n", FNAME);

View File

@@ -1,7 +1,7 @@
import re
def _run_all(self, numprocs, fstype, tests, testtype):
def _run_all(self, fstype, tests, testtype):
testdir = self.mkworkdir('d')
share = "rem Internal share" if self.version == "FDPP kernel" else "c:\\share"
@@ -9,10 +9,7 @@ def _run_all(self, numprocs, fstype, tests, testtype):
tfile = "set LFN=n\r\n" + "d:\r\n" + share + "\r\n"
for t in tests:
args = t + (testtype,)
if numprocs == "ONE":
tfile += ("c:\\shardlrn single %s %s %s %s\r\n" % args)
else:
tfile += ("c:\\shardlrn primary %s %s %s %s\r\n" % args)
tfile += ("c:\\shardlrn primary %s %s %s %s\r\n" % args)
tfile += "rem tests complete\r\n"
tfile += "rem end\r\n"
@@ -69,13 +66,8 @@ unsigned short openmode(const char *s) {
int main(int argc, char *argv[]) {
int handle;
int ret;
enum {
PRIMARY,
SECONDARY,
SINGLE,
} ptype;
unsigned short smode, omode;
int primary = -1;
unsigned short prismode, priomode;
enum {
DELFCB,
RENFCB,
@@ -85,29 +77,27 @@ int main(int argc, char *argv[]) {
} testmode;
if (argc < 6) {
printf("FAIL: Missing arguments (primary|secondary|single) sharemode openmode expected (DELFCB|RENFCB|DELPTH|RENPTH|SETATT)\n");
printf("FAIL: Missing arguments (primary|secondary) prismode priomode expected (DELFCB|RENFCB|DELPTH|RENPTH|SETATT)\n");
return -2;
}
if (strcmp(argv[1], "primary") == 0)
ptype = PRIMARY;
else if (strcmp(argv[1], "secondary") == 0)
ptype = SECONDARY;
else if (strcmp(argv[1], "single") == 0)
ptype = SINGLE;
else {
printf("FAIL: Invalid argument (primary|secondary|single)\n");
primary = 1;
if (strcmp(argv[1], "secondary") == 0)
primary = 0;
if (primary < 0) {
printf("FAIL: Invalid argument (primary|secondary)\n");
return -2;
}
smode = sharemode(argv[2]);
if (smode == 0xff) {
printf("FAIL: Invalid argument sharemode '%s'\n", argv[2]);
prismode = sharemode(argv[2]);
if (prismode == 0xff) {
printf("FAIL: Invalid argument prismode '%s'\n", argv[2]);
return -2;
}
omode = openmode(argv[3]);
if (omode == 0xff) {
printf("FAIL: Invalid argument openmode '%s'\n", argv[3]);
priomode = openmode(argv[3]);
if (priomode == 0xff) {
printf("FAIL: Invalid argument priomode '%s'\n", argv[3]);
return -2;
}
@@ -131,8 +121,8 @@ int main(int argc, char *argv[]) {
// Print results in consistent format
// FAIL:("SH_DENYNO", "RW", "ALLOW")[secondary denied]
if (ptype == PRIMARY || ptype == SINGLE) {
unsigned short mode = smode | omode;
if (primary) {
unsigned short mode = prismode | priomode;
// remove the source file so we can create it anew
unlink(FN1 "." FE1);
@@ -156,19 +146,12 @@ int main(int argc, char *argv[]) {
}
// printf("INFO: primary: File was opened with mode 0x%04x\n", mode);
}
if (ptype == PRIMARY) {
// Now start second copy
spawnlp(P_WAIT, argv[0], argv[0], "secondary", argv[2], argv[3], argv[4], argv[5], NULL);
_dos_close(handle);
return 0;
}
if (ptype == SECONDARY || ptype == SINGLE) {
} else { // secondary
switch(testmode) {
case DELFCB: {
@@ -347,7 +330,7 @@ int main(int argc, char *argv[]) {
break;
}
} // switch
}
if (ret != 0) {
if (strcmp(argv[4], "DENY") == 0) {
@@ -368,10 +351,6 @@ int main(int argc, char *argv[]) {
}
}
if (ptype == SINGLE) {
_dos_close(handle);
}
return 0;
}
""")
@@ -385,29 +364,7 @@ int main(int argc, char *argv[]) {
return self.runDosemu("testit.bat", config=config, timeout=60)
TESTS_ONE_PROCESS = (
("SH_COMPAT", "R" , "ALLOW"),
("SH_COMPAT", "W" , "ALLOW"),
("SH_COMPAT", "RW", "ALLOW"),
("SH_DENYRW", "R" , "DENY"),
("SH_DENYRW", "W" , "DENY"),
("SH_DENYRW", "RW", "DENY"),
("SH_DENYWR", "R" , "DENY"),
("SH_DENYWR", "W" , "DENY"),
("SH_DENYWR", "RW", "DENY"),
("SH_DENYRD", "R" , "DENY"),
("SH_DENYRD", "W" , "DENY"),
("SH_DENYRD", "RW", "DENY"),
("SH_DENYNO", "R" , "DENY"),
("SH_DENYNO", "W" , "DENY"),
("SH_DENYNO", "RW", "DENY"),
)
TESTS_TWO_PROCESS_FAT = (
DELRENTESTS = (
("SH_COMPAT", "R" , "DENY"),
("SH_COMPAT", "W" , "DENY"),
("SH_COMPAT", "RW", "DENY"),
@@ -429,27 +386,14 @@ TESTS_TWO_PROCESS_FAT = (
("SH_DENYNO", "RW", "DENY"),
)
# SH_COMPAT makes no sense on network drive, see
# https://github.com/dosemu2/dosemu2/pull/1623#issuecomment-1108776612
TESTS_TWO_PROCESS_MFS = tuple(TESTS_TWO_PROCESS_FAT)[3:]
def _check_single_result(self, results, t):
m = re.search("FAIL:\('%s', '%s', '%s'\)\[.*\]" % t, results)
if m:
self.fail(msg=m.group(0))
def ds3_share_open_access(self, numprocs, fstype, testtype):
if numprocs == "ONE":
tests = TESTS_ONE_PROCESS
else: # TWO
if fstype == "MFS":
tests = TESTS_TWO_PROCESS_MFS
else: # FAT
tests = TESTS_TWO_PROCESS_FAT
results = _run_all(self, numprocs, fstype, tests, testtype)
for t in tests:
def ds3_share_open_access(self, fstype, testtype):
results = _run_all(self, fstype, DELRENTESTS, testtype)
for t in DELRENTESTS:
with self.subTest(t=t):
_check_single_result(self, results, t)
self.assertIn("rem tests complete", results)

View File

@@ -187,7 +187,7 @@ int main(int argc, char *argv[]) {
# 1 = open succeeds if file read-only, else fails with error code.
# 2 = open succeeds if file read-only, else fails with INT 24
OPEN_622 = (
OPENTESTS = (
# Compat R |Y Y Y N N N 1 N N N N N 1 N N.
("SH_COMPAT", "R" , "SH_COMPAT", "R" , "ALLOW"),
("SH_COMPAT", "R" , "SH_COMPAT", "W" , "ALLOW"),
@@ -444,277 +444,14 @@ OPEN_622 = (
("SH_DENYNO", "RW", "SH_DENYNO", "RW", "ALLOW"),
)
OPEN_HYBRID = (
# Compat R |Y Y Y N N N 1 N N N N N 1 N N.
("SH_COMPAT", "R" , "SH_COMPAT", "R" , "ALLOW"),
("SH_COMPAT", "R" , "SH_COMPAT", "W" , "ALLOW"),
("SH_COMPAT", "R" , "SH_COMPAT", "RW", "ALLOW"),
("SH_COMPAT", "R" , "SH_DENYRW", "R" , "DENY"),
("SH_COMPAT", "R" , "SH_DENYRW", "W" , "DENY"),
("SH_COMPAT", "R" , "SH_DENYRW", "RW", "DENY"),
("SH_COMPAT", "R" , "SH_DENYWR", "R" , "ALLOW"), # File RO success, W fails. For MS-DOS-7: always success.
("SH_COMPAT", "R" , "SH_DENYWR", "W" , "DENY"),
("SH_COMPAT", "R" , "SH_DENYWR", "RW", "DENY"),
("SH_COMPAT", "R" , "SH_DENYRD", "R" , "DENY"),
("SH_COMPAT", "R" , "SH_DENYRD", "W" , "DENY"),
("SH_COMPAT", "R" , "SH_DENYRD", "RW", "DENY"),
("SH_COMPAT", "R" , "SH_DENYNO", "R" , "ALLOW"), # File RO success, W fails. For MS-DOS-7: always success.
("SH_COMPAT", "R" , "SH_DENYNO", "W" , "DENY"),
("SH_COMPAT", "R" , "SH_DENYNO", "RW", "DENY"),
# W |Y Y Y N N N N N N N N N N N N.
("SH_COMPAT", "W" , "SH_COMPAT", "R" , "ALLOW"),
("SH_COMPAT", "W" , "SH_COMPAT", "W" , "ALLOW"),
("SH_COMPAT", "W" , "SH_COMPAT", "RW", "ALLOW"),
("SH_COMPAT", "W" , "SH_DENYRW", "R" , "DENY"),
("SH_COMPAT", "W" , "SH_DENYRW", "W" , "DENY"),
("SH_COMPAT", "W" , "SH_DENYRW", "RW", "DENY"),
("SH_COMPAT", "W" , "SH_DENYWR", "R" , "DENY"),
("SH_COMPAT", "W" , "SH_DENYWR", "W" , "DENY"),
("SH_COMPAT", "W" , "SH_DENYWR", "RW", "DENY"),
("SH_COMPAT", "W" , "SH_DENYRD", "R" , "DENY"),
("SH_COMPAT", "W" , "SH_DENYRD", "W" , "DENY"),
("SH_COMPAT", "W" , "SH_DENYRD", "RW", "DENY"),
("SH_COMPAT", "W" , "SH_DENYNO", "R" , "DENY"),
("SH_COMPAT", "W" , "SH_DENYNO", "W" , "DENY"),
("SH_COMPAT", "W" , "SH_DENYNO", "RW", "DENY"),
# RW|Y Y Y N N N N N N N N N N N N
("SH_COMPAT", "RW", "SH_COMPAT", "R" , "ALLOW"),
("SH_COMPAT", "RW", "SH_COMPAT", "W" , "ALLOW"),
("SH_COMPAT", "RW", "SH_COMPAT", "RW", "ALLOW"),
("SH_COMPAT", "RW", "SH_DENYRW", "R" , "DENY"),
("SH_COMPAT", "RW", "SH_DENYRW", "W" , "DENY"),
("SH_COMPAT", "RW", "SH_DENYRW", "RW", "DENY"),
("SH_COMPAT", "RW", "SH_DENYWR", "R" , "DENY"),
("SH_COMPAT", "RW", "SH_DENYWR", "W" , "DENY"),
("SH_COMPAT", "RW", "SH_DENYWR", "RW", "DENY"),
("SH_COMPAT", "RW", "SH_DENYRD", "R" , "DENY"),
("SH_COMPAT", "RW", "SH_DENYRD", "W" , "DENY"),
("SH_COMPAT", "RW", "SH_DENYRD", "RW", "DENY"),
("SH_COMPAT", "RW", "SH_DENYNO", "R" , "DENY"),
("SH_COMPAT", "RW", "SH_DENYNO", "W" , "DENY"),
("SH_COMPAT", "RW", "SH_DENYNO", "RW", "DENY"),
# Deny R |C C C N N N N N N N N N N N N
("SH_DENYRW", "R" , "SH_COMPAT", "R" , "INT24"),
("SH_DENYRW", "R" , "SH_COMPAT", "W" , "INT24"),
("SH_DENYRW", "R" , "SH_COMPAT", "RW", "INT24"),
("SH_DENYRW", "R" , "SH_DENYRW", "R" , "DENY"),
("SH_DENYRW", "R" , "SH_DENYRW", "W" , "DENY"),
("SH_DENYRW", "R" , "SH_DENYRW", "RW", "DENY"),
("SH_DENYRW", "R" , "SH_DENYWR", "R" , "DENY"),
("SH_DENYRW", "R" , "SH_DENYWR", "W" , "DENY"),
("SH_DENYRW", "R" , "SH_DENYWR", "RW", "DENY"),
("SH_DENYRW", "R" , "SH_DENYRD", "R" , "DENY"),
("SH_DENYRW", "R" , "SH_DENYRD", "W" , "DENY"),
("SH_DENYRW", "R" , "SH_DENYRD", "RW", "DENY"),
("SH_DENYRW", "R" , "SH_DENYNO", "R" , "DENY"),
("SH_DENYRW", "R" , "SH_DENYNO", "W" , "DENY"),
("SH_DENYRW", "R" , "SH_DENYNO", "RW", "DENY"),
# All W |C C C N N N N N N N N N N N N.
("SH_DENYRW", "W" , "SH_COMPAT", "R" , "INT24"),
("SH_DENYRW", "W" , "SH_COMPAT", "W" , "INT24"),
("SH_DENYRW", "W" , "SH_COMPAT", "RW", "INT24"),
("SH_DENYRW", "W" , "SH_DENYRW", "R" , "DENY"),
("SH_DENYRW", "W" , "SH_DENYRW", "W" , "DENY"),
("SH_DENYRW", "W" , "SH_DENYRW", "RW", "DENY"),
("SH_DENYRW", "W" , "SH_DENYWR", "R" , "DENY"),
("SH_DENYRW", "W" , "SH_DENYWR", "W" , "DENY"),
("SH_DENYRW", "W" , "SH_DENYWR", "RW", "DENY"),
("SH_DENYRW", "W" , "SH_DENYRD", "R" , "DENY"),
("SH_DENYRW", "W" , "SH_DENYRD", "W" , "DENY"),
("SH_DENYRW", "W" , "SH_DENYRD", "RW", "DENY"),
("SH_DENYRW", "W" , "SH_DENYNO", "R" , "DENY"),
("SH_DENYRW", "W" , "SH_DENYNO", "W" , "DENY"),
("SH_DENYRW", "W" , "SH_DENYNO", "RW", "DENY"),
# RW|C C C N N N N N N N N N N N N
("SH_DENYRW", "RW", "SH_COMPAT", "R" , "INT24"),
("SH_DENYRW", "RW", "SH_COMPAT", "W" , "INT24"),
("SH_DENYRW", "RW", "SH_COMPAT", "RW", "INT24"),
("SH_DENYRW", "RW", "SH_DENYRW", "R" , "DENY"),
("SH_DENYRW", "RW", "SH_DENYRW", "W" , "DENY"),
("SH_DENYRW", "RW", "SH_DENYRW", "RW", "DENY"),
("SH_DENYRW", "RW", "SH_DENYWR", "R" , "DENY"),
("SH_DENYRW", "RW", "SH_DENYWR", "W" , "DENY"),
("SH_DENYRW", "RW", "SH_DENYWR", "RW", "DENY"),
("SH_DENYRW", "RW", "SH_DENYRD", "R" , "DENY"),
("SH_DENYRW", "RW", "SH_DENYRD", "W" , "DENY"),
("SH_DENYRW", "RW", "SH_DENYRD", "RW", "DENY"),
("SH_DENYRW", "RW", "SH_DENYNO", "R" , "DENY"),
("SH_DENYRW", "RW", "SH_DENYNO", "W" , "DENY"),
("SH_DENYRW", "RW", "SH_DENYNO", "RW", "DENY"),
# Deny R |2 C C N N N Y N N N N N Y N N
("SH_DENYWR", "R" , "SH_COMPAT", "R" , "ALLOW"), # File RO success, W fails INT24. For MS-DOS-7: always success.
("SH_DENYWR", "R" , "SH_COMPAT", "W" , "INT24"),
("SH_DENYWR", "R" , "SH_COMPAT", "RW", "INT24"),
("SH_DENYWR", "R" , "SH_DENYRW", "R" , "DENY"),
("SH_DENYWR", "R" , "SH_DENYRW", "W" , "DENY"),
("SH_DENYWR", "R" , "SH_DENYRW", "RW", "DENY"),
("SH_DENYWR", "R" , "SH_DENYWR", "R" , "ALLOW"),
("SH_DENYWR", "R" , "SH_DENYWR", "W" , "DENY"),
("SH_DENYWR", "R" , "SH_DENYWR", "RW", "DENY"),
("SH_DENYWR", "R" , "SH_DENYRD", "R" , "DENY"),
("SH_DENYWR", "R" , "SH_DENYRD", "W" , "DENY"),
("SH_DENYWR", "R" , "SH_DENYRD", "RW", "DENY"),
("SH_DENYWR", "R" , "SH_DENYNO", "R" , "ALLOW"),
("SH_DENYWR", "R" , "SH_DENYNO", "W" , "DENY"),
("SH_DENYWR", "R" , "SH_DENYNO", "RW", "DENY"),
# Write W |C C C N N N N N N Y N N Y N N.
("SH_DENYWR", "W" , "SH_COMPAT", "R" , "INT24"),
("SH_DENYWR", "W" , "SH_COMPAT", "W" , "INT24"),
("SH_DENYWR", "W" , "SH_COMPAT", "RW", "INT24"),
("SH_DENYWR", "W" , "SH_DENYRW", "R" , "DENY"),
("SH_DENYWR", "W" , "SH_DENYRW", "W" , "DENY"),
("SH_DENYWR", "W" , "SH_DENYRW", "RW", "DENY"),
("SH_DENYWR", "W" , "SH_DENYWR", "R" , "DENY"),
("SH_DENYWR", "W" , "SH_DENYWR", "W" , "DENY"),
("SH_DENYWR", "W" , "SH_DENYWR", "RW", "DENY"),
("SH_DENYWR", "W" , "SH_DENYRD", "R" , "ALLOW"),
("SH_DENYWR", "W" , "SH_DENYRD", "W" , "DENY"),
("SH_DENYWR", "W" , "SH_DENYRD", "RW", "DENY"),
("SH_DENYWR", "W" , "SH_DENYNO", "R" , "ALLOW"),
("SH_DENYWR", "W" , "SH_DENYNO", "W" , "DENY"),
("SH_DENYWR", "W" , "SH_DENYNO", "RW", "DENY"),
# RW|C C C N N N N N N N N N Y N N
("SH_DENYWR", "RW", "SH_COMPAT", "R" , "INT24"),
("SH_DENYWR", "RW", "SH_COMPAT", "W" , "INT24"),
("SH_DENYWR", "RW", "SH_COMPAT", "RW", "INT24"),
("SH_DENYWR", "RW", "SH_DENYRW", "R" , "DENY"),
("SH_DENYWR", "RW", "SH_DENYRW", "W" , "DENY"),
("SH_DENYWR", "RW", "SH_DENYRW", "RW", "DENY"),
("SH_DENYWR", "RW", "SH_DENYWR", "R" , "DENY"),
("SH_DENYWR", "RW", "SH_DENYWR", "W" , "DENY"),
("SH_DENYWR", "RW", "SH_DENYWR", "RW", "DENY"),
("SH_DENYWR", "RW", "SH_DENYRD", "R" , "DENY"),
("SH_DENYWR", "RW", "SH_DENYRD", "W" , "DENY"),
("SH_DENYWR", "RW", "SH_DENYRD", "RW", "DENY"),
("SH_DENYWR", "RW", "SH_DENYNO", "R" , "ALLOW"),
("SH_DENYWR", "RW", "SH_DENYNO", "W" , "DENY"),
("SH_DENYWR", "RW", "SH_DENYNO", "RW", "DENY"),
# Deny R |C C C N N N N Y N N N N N Y N
("SH_DENYRD", "R" , "SH_COMPAT", "R" , "INT24"),
("SH_DENYRD", "R" , "SH_COMPAT", "W" , "INT24"),
("SH_DENYRD", "R" , "SH_COMPAT", "RW", "INT24"),
("SH_DENYRD", "R" , "SH_DENYRW", "R" , "DENY"),
("SH_DENYRD", "R" , "SH_DENYRW", "W" , "DENY"),
("SH_DENYRD", "R" , "SH_DENYRW", "RW", "DENY"),
("SH_DENYRD", "R" , "SH_DENYWR", "R" , "DENY"),
("SH_DENYRD", "R" , "SH_DENYWR", "W" , "ALLOW"),
("SH_DENYRD", "R" , "SH_DENYWR", "RW", "DENY"),
("SH_DENYRD", "R" , "SH_DENYRD", "R" , "DENY"),
("SH_DENYRD", "R" , "SH_DENYRD", "W" , "DENY"),
("SH_DENYRD", "R" , "SH_DENYRD", "RW", "DENY"),
("SH_DENYRD", "R" , "SH_DENYNO", "R" , "DENY"),
("SH_DENYRD", "R" , "SH_DENYNO", "W" , "ALLOW"),
("SH_DENYRD", "R" , "SH_DENYNO", "RW", "DENY"),
# Read W |C C C N N N N N N N Y N N Y N.
("SH_DENYRD", "W" , "SH_COMPAT", "R" , "INT24"),
("SH_DENYRD", "W" , "SH_COMPAT", "W" , "INT24"),
("SH_DENYRD", "W" , "SH_COMPAT", "RW", "INT24"),
("SH_DENYRD", "W" , "SH_DENYRW", "R" , "DENY"),
("SH_DENYRD", "W" , "SH_DENYRW", "W" , "DENY"),
("SH_DENYRD", "W" , "SH_DENYRW", "RW", "DENY"),
("SH_DENYRD", "W" , "SH_DENYWR", "R" , "DENY"),
("SH_DENYRD", "W" , "SH_DENYWR", "W" , "DENY"),
("SH_DENYRD", "W" , "SH_DENYWR", "RW", "DENY"),
("SH_DENYRD", "W" , "SH_DENYRD", "R" , "DENY"),
("SH_DENYRD", "W" , "SH_DENYRD", "W" , "ALLOW"),
("SH_DENYRD", "W" , "SH_DENYRD", "RW", "DENY"),
("SH_DENYRD", "W" , "SH_DENYNO", "R" , "DENY"),
("SH_DENYRD", "W" , "SH_DENYNO", "W" , "ALLOW"),
("SH_DENYRD", "W" , "SH_DENYNO", "RW", "DENY"),
# RW|C C C N N N N N N N N N N Y N
("SH_DENYRD", "RW", "SH_COMPAT", "R" , "INT24"),
("SH_DENYRD", "RW", "SH_COMPAT", "W" , "INT24"),
("SH_DENYRD", "RW", "SH_COMPAT", "RW", "INT24"),
("SH_DENYRD", "RW", "SH_DENYRW", "R" , "DENY"),
("SH_DENYRD", "RW", "SH_DENYRW", "W" , "DENY"),
("SH_DENYRD", "RW", "SH_DENYRW", "RW", "DENY"),
("SH_DENYRD", "RW", "SH_DENYWR", "R" , "DENY"),
("SH_DENYRD", "RW", "SH_DENYWR", "W" , "DENY"),
("SH_DENYRD", "RW", "SH_DENYWR", "RW", "DENY"),
("SH_DENYRD", "RW", "SH_DENYRD", "R" , "DENY"),
("SH_DENYRD", "RW", "SH_DENYRD", "W" , "DENY"),
("SH_DENYRD", "RW", "SH_DENYRD", "RW", "DENY"),
("SH_DENYRD", "RW", "SH_DENYNO", "R" , "DENY"),
("SH_DENYRD", "RW", "SH_DENYNO", "W" , "ALLOW"),
("SH_DENYRD", "RW", "SH_DENYNO", "RW", "DENY"),
# Deny R |2 C C N N N Y Y Y N N N Y Y Y
("SH_DENYNO", "R" , "SH_COMPAT", "R" , "ALLOW"), # File RO success, W fails INT24. For MS-DOS-7: always success.
("SH_DENYNO", "R" , "SH_COMPAT", "W" , "INT24"),
("SH_DENYNO", "R" , "SH_COMPAT", "RW", "INT24"),
("SH_DENYNO", "R" , "SH_DENYRW", "R" , "DENY"),
("SH_DENYNO", "R" , "SH_DENYRW", "W" , "DENY"),
("SH_DENYNO", "R" , "SH_DENYRW", "RW", "DENY"),
("SH_DENYNO", "R" , "SH_DENYWR", "R" , "ALLOW"),
("SH_DENYNO", "R" , "SH_DENYWR", "W" , "ALLOW"),
("SH_DENYNO", "R" , "SH_DENYWR", "RW", "ALLOW"),
("SH_DENYNO", "R" , "SH_DENYRD", "R" , "DENY"),
("SH_DENYNO", "R" , "SH_DENYRD", "W" , "DENY"),
("SH_DENYNO", "R" , "SH_DENYRD", "RW", "DENY"),
("SH_DENYNO", "R" , "SH_DENYNO", "R" , "ALLOW"),
("SH_DENYNO", "R" , "SH_DENYNO", "W" , "ALLOW"),
("SH_DENYNO", "R" , "SH_DENYNO", "RW", "ALLOW"),
# None W |C C C N N N N N N Y Y Y Y Y Y.
("SH_DENYNO", "W" , "SH_COMPAT", "R" , "INT24"),
("SH_DENYNO", "W" , "SH_COMPAT", "W" , "INT24"),
("SH_DENYNO", "W" , "SH_COMPAT", "RW", "INT24"),
("SH_DENYNO", "W" , "SH_DENYRW", "R" , "DENY"),
("SH_DENYNO", "W" , "SH_DENYRW", "W" , "DENY"),
("SH_DENYNO", "W" , "SH_DENYRW", "RW", "DENY"),
("SH_DENYNO", "W" , "SH_DENYWR", "R" , "DENY"),
("SH_DENYNO", "W" , "SH_DENYWR", "W" , "DENY"),
("SH_DENYNO", "W" , "SH_DENYWR", "RW", "DENY"),
("SH_DENYNO", "W" , "SH_DENYRD", "R" , "ALLOW"),
("SH_DENYNO", "W" , "SH_DENYRD", "W" , "ALLOW"),
("SH_DENYNO", "W" , "SH_DENYRD", "RW", "ALLOW"),
("SH_DENYNO", "W" , "SH_DENYNO", "R" , "ALLOW"),
("SH_DENYNO", "W" , "SH_DENYNO", "W" , "ALLOW"),
("SH_DENYNO", "W" , "SH_DENYNO", "RW", "ALLOW"),
# RW|C C C N N N N N N N N N Y Y Y
("SH_DENYNO", "RW", "SH_COMPAT", "R" , "INT24"),
("SH_DENYNO", "RW", "SH_COMPAT", "W" , "INT24"),
("SH_DENYNO", "RW", "SH_COMPAT", "RW", "INT24"),
("SH_DENYNO", "RW", "SH_DENYRW", "R" , "DENY"),
("SH_DENYNO", "RW", "SH_DENYRW", "W" , "DENY"),
("SH_DENYNO", "RW", "SH_DENYRW", "RW", "DENY"),
("SH_DENYNO", "RW", "SH_DENYWR", "R" , "DENY"),
("SH_DENYNO", "RW", "SH_DENYWR", "W" , "DENY"),
("SH_DENYNO", "RW", "SH_DENYWR", "RW", "DENY"),
("SH_DENYNO", "RW", "SH_DENYRD", "R" , "DENY"),
("SH_DENYNO", "RW", "SH_DENYRD", "W" , "DENY"),
("SH_DENYNO", "RW", "SH_DENYRD", "RW", "DENY"),
("SH_DENYNO", "RW", "SH_DENYNO", "R" , "ALLOW"),
("SH_DENYNO", "RW", "SH_DENYNO", "W" , "ALLOW"),
("SH_DENYNO", "RW", "SH_DENYNO", "RW", "ALLOW"),
)
def _check_single_result(self, results, t):
m = re.search("FAIL:\('%s', '%s', '%s', '%s', '%s'\)\[.*\]" % t, results)
if m:
self.fail(msg=m.group(0))
def ds3_share_open_twice(self, fstype):
if 'FDPP' in self.version or fstype == 'MFS':
tests = OPEN_HYBRID
else:
tests = OPEN_622
results = _run_all(self, fstype, tests)
for t in tests:
results = _run_all(self, fstype, OPENTESTS)
for t in OPENTESTS:
with self.subTest(t=t):
_check_single_result(self, results, t)
self.assertIn("rem tests complete", results)

View File

@@ -1,676 +0,0 @@
# Note label setting is currently disabled on MFS
from subprocess import check_output, STDOUT
from common_framework import IMAGEDIR
def label_create(self, fstype, itype):
testdir = self.mkworkdir('d')
name = 'sentinel'
preop = ''
postop = ''
fat = '12'
if itype is None or itype == 'bpb12':
pass
elif itype == 'bpb16':
fat = '16'
elif itype == 'bpb32':
fat = '32'
elif itype == 'prefile':
preop += 'echo a >> %s' % name
elif itype == 'predir':
preop += 'mkdir %s' % name
elif itype == 'postfile':
postop += 'echo a >> %s' % name
elif itype == 'postdir':
postop += 'mkdir %s' % name
else:
raise ValueError
if fstype == "MFS":
config = """\
$_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1"
$_floppy_a = ""
"""
else: # FAT
config = """\
$_hdimage = "dXXXXs/c:hdtype1 %s:partition +1"
$_floppy_a = ""
""" % self.mkimage_vbr(fat, cwd=testdir)
self.mkfile("testit.bat", """\
d:
%s
c:\\labcreat
%s
DIR
rem end
""" % (preop, postop), newline="\r\n")
self.mkcom_with_ia16("labcreat", r"""
#include <dos.h>
#include <stdio.h>
#include <string.h>
struct {
uint8_t sig;
uint8_t pad[5];
uint8_t attr;
struct _fcb x;
/*
char _fcb_drive;
char _fcb_name[8];
char _fcb_ext[3];
short _fcb_curblk;
short _fcb_recsize;
long _fcb_filsize;
short _fcb_date;
char _fcb_resv[10];
char _fcb_currec;
long _fcb_random;
*/
} __attribute__((packed)) xfcb;
int main(int argc, char *argv[])
{
union REGS r = {};
xfcb.sig = 0xff;
xfcb.attr = _A_VOLID;
xfcb.x._fcb_drive = 0;
memcpy(xfcb.x._fcb_name, "????????", 8); // delete
memcpy(xfcb.x._fcb_ext, "???", 3);
r.x.ax = 0x1300;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
/* don't check result, there might not be anything to delete */
memcpy(xfcb.x._fcb_name, "%s", 8); // create
memcpy(xfcb.x._fcb_ext, " ", 3);
r.x.ax = 0x1600;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On creation\n");
return 1;
}
r.x.ax = 0x1000; // close
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On close\n");
return 1;
}
printf("PASS: Operation success\n");
return 0;
}
""" % name)
results = self.runDosemu("testit.bat", config=config)
self.assertIn("PASS: Operation success", results)
self.assertRegex(results, "Volume in drive [Dd] is %s" % name.upper())
if itype in ['prefile', 'postfile']:
# 2022-09-03 12:59 4 SENTINEL
# SENTINEL 4 09-03-22 1:00p
# SENTINEL 4 9-03-22 1:01p
# SENTINEL 4 9-03-22 11:01
self.assertRegex(results.upper(),
r"\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}\s+4\s+%s"
r"|"
r"%s\s+4\s+\d{1,2}-\d{1,2}-\d{2}\s+\d+:\d+[AaPp]?" %
(name.upper(), name.upper()))
elif itype in ['predir', 'postdir']:
# 2019-06-27 11:29 <DIR> DOSEMU
# DOSEMU <DIR> 06-27-19 5:33p
# TESTB <DIR> 8-17-20 2:03p
# TESTB <DIR> 8-17-20 12:03
self.assertRegex(results.upper(),
r"\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}\s<DIR>\s+%s"
r"|"
r"%s\s+<DIR>\s+\d{1,2}-\d{1,2}-\d{2}\s+\d+:\d+[AaPp]?" %
(name.upper(), name.upper()))
elif itype in ['bpb12', 'bpb16', 'bpb32']:
fat = itype[3:5]
img = self.topdir / IMAGEDIR / ("fat%s.img" % fat)
data = img.read_bytes()
if data[0x26] == 0x29: # v4 BPB
v1 = 0x2b
v2 = v1 + len(name)
self.assertEqual(data[v1:v2], bytes(name.upper(), encoding='ascii'))
elif data[0x42] == 0x29: # v7.1 BPB
v1 = 0x47
v2 = v1 + len(name)
self.assertEqual(data[v1:v2], bytes(name.upper(), encoding='ascii'))
else:
self.fail("No BPB signature found")
def label_create_noduplicate(self, fstype):
testdir = self.mkworkdir('d')
if fstype == "MFS":
config = """\
$_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1"
$_floppy_a = ""
"""
else: # FAT
config = """\
$_hdimage = "dXXXXs/c:hdtype1 %s:partition +1"
$_floppy_a = ""
""" % self.mkimage_vbr("12", cwd=testdir)
self.mkfile("testit.bat", """\
d:
c:\\labdupli
DIR
rem end
""", newline="\r\n")
self.mkcom_with_ia16("labdupli", r"""
#include <dos.h>
#include <stdio.h>
#include <string.h>
struct {
uint8_t sig;
uint8_t pad[5];
uint8_t attr;
struct _fcb x;
/*
char _fcb_drive;
char _fcb_name[8];
char _fcb_ext[3];
short _fcb_curblk;
short _fcb_recsize;
long _fcb_filsize;
short _fcb_date;
char _fcb_resv[10];
char _fcb_currec;
long _fcb_random;
*/
} __attribute__((packed)) xfcb;
int main(int argc, char *argv[])
{
union REGS r = {};
xfcb.sig = 0xff;
xfcb.attr = _A_VOLID;
xfcb.x._fcb_drive = 0;
memcpy(xfcb.x._fcb_name, "????????", 8); // delete
memcpy(xfcb.x._fcb_ext, "???", 3);
r.x.ax = 0x1300;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
/* don't check result, there might not be anything to delete */
memcpy(xfcb.x._fcb_name, "INITIAL ", 8); // create
memcpy(xfcb.x._fcb_ext, " ", 3);
r.x.ax = 0x1600;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On initial creation\n");
return 1;
}
r.x.ax = 0x1000; // close
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On initial close\n");
return 1;
}
memcpy(xfcb.x._fcb_name, "DUPLICAT", 8); // create duplicate
memcpy(xfcb.x._fcb_ext, " ", 3);
r.x.ax = 0x1600;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al == 0) {
printf("FAIL: Allowed duplicate creation\n");
r.x.ax = 0x1000; // close
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
/* don't check result, there's nothing we can do about it. */
return 1;
} else {
printf("INFO: Denied duplicate creation (0x%02x)\n", r.h.al);
}
printf("PASS: Operation success\n");
return 0;
}
""")
results = self.runDosemu("testit.bat", config=config)
self.assertIn("PASS: Operation success", results)
self.assertRegex(results, "Volume in drive [Dd] is INITIAL")
self.assertIn("INFO: Denied duplicate creation (0xff)", results)
def label_create_nonrootdir(self, fstype):
testdir = self.mkworkdir('d')
if fstype == "MFS":
config = """\
$_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1"
$_floppy_a = ""
"""
else: # FAT
config = """\
$_hdimage = "dXXXXs/c:hdtype1 %s:partition +1"
$_floppy_a = ""
""" % self.mkimage_vbr("12", cwd=testdir)
self.mkfile("testit.bat", """\
d:
cd \\
mkdir x
cd x
c:\\labnonrt
DIR
rem end
""", newline="\r\n")
self.mkcom_with_ia16("labnonrt", r"""
#include <dos.h>
#include <stdio.h>
#include <string.h>
struct {
uint8_t sig;
uint8_t pad[5];
uint8_t attr;
struct _fcb x;
/*
char _fcb_drive;
char _fcb_name[8];
char _fcb_ext[3];
short _fcb_curblk;
short _fcb_recsize;
long _fcb_filsize;
short _fcb_date;
char _fcb_resv[10];
char _fcb_currec;
long _fcb_random;
*/
} __attribute__((packed)) xfcb;
int main(int argc, char *argv[])
{
union REGS r = {};
xfcb.sig = 0xff;
xfcb.attr = _A_VOLID;
xfcb.x._fcb_drive = 0;
memcpy(xfcb.x._fcb_name, "TEST LAB", 8); // create in non root
memcpy(xfcb.x._fcb_ext, "EL1", 3);
r.x.ax = 0x1600;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al == 0) {
printf("INFO: Allowed non root creation\n");
r.x.ax = 0x1000; // close
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
/* don't check result, there's nothing we can do about it. */
} else {
printf("FAIL: Denied non root creation (0x%02x)\n", r.h.al);
return 1;
}
printf("PASS: Operation success\n");
return 0;
}
""")
results = self.runDosemu("testit.bat", config=config)
self.assertIn("PASS: Operation success", results)
self.assertRegex(results, "Volume in drive [Dd] is TEST LABEL1")
self.assertNotIn("FAIL: Denied non root creation", results)
def label_delete_wildcard(self, fstype):
testdir = self.mkworkdir('d')
if fstype == "MFS":
config = """\
$_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1"
$_floppy_a = ""
"""
else: # FAT
config = """\
$_hdimage = "dXXXXs/c:hdtype1 %s:partition +1"
$_floppy_a = ""
""" % self.mkimage_vbr("12", cwd=testdir)
self.mkfile("testit.bat", """\
d:
c:\\labdelw
DIR
rem end
""", newline="\r\n")
self.mkcom_with_ia16("labdelw", r"""
#include <dos.h>
#include <stdio.h>
#include <string.h>
struct {
uint8_t sig;
uint8_t pad[5];
uint8_t attr;
struct _fcb x;
/*
char _fcb_drive;
char _fcb_name[8];
char _fcb_ext[3];
short _fcb_curblk;
short _fcb_recsize;
long _fcb_filsize;
short _fcb_date;
char _fcb_resv[10];
char _fcb_currec;
long _fcb_random;
*/
} __attribute__((packed)) xfcb;
int main(int argc, char *argv[])
{
union REGS r = {};
xfcb.sig = 0xff;
xfcb.attr = _A_VOLID;
xfcb.x._fcb_drive = 0;
memcpy(xfcb.x._fcb_name, "????????", 8); // delete
memcpy(xfcb.x._fcb_ext, "???", 3);
r.x.ax = 0x1300;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
/* don't check result, there might not be anything to delete */
memcpy(xfcb.x._fcb_name, "INITIAL ", 8); // create
memcpy(xfcb.x._fcb_ext, " ", 3);
r.x.ax = 0x1600;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On initial creation\n");
return 1;
}
r.x.ax = 0x1000; // close
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On initial close\n");
return 1;
}
memcpy(xfcb.x._fcb_name, "????????", 8); // delete with wildcard
memcpy(xfcb.x._fcb_ext, "???", 3);
r.x.ax = 0x1300;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On delete with wildcard\n");
return 1;
}
printf("PASS: Operation success\n");
return 0;
}
""")
results = self.runDosemu("testit.bat", config=config)
self.assertIn("PASS: Operation success", results)
self.assertRegex(results, "Volume.*(has no|does not have a) label")
self.assertNotIn("FAIL:", results)
def label_delete_recreate(self, fstype):
testdir = self.mkworkdir('d')
if fstype == "MFS":
config = """\
$_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d:hdtype1 +1"
$_floppy_a = ""
"""
else: # FAT
config = """\
$_hdimage = "dXXXXs/c:hdtype1 %s:partition +1"
$_floppy_a = ""
""" % self.mkimage_vbr("12", cwd=testdir)
self.mkfile("testit.bat", """\
d:
c:\\labdelr
DIR
rem end
""", newline="\r\n")
self.mkcom_with_ia16("labdelr", r"""
#include <dos.h>
#include <stdio.h>
#include <string.h>
struct {
uint8_t sig;
uint8_t pad[5];
uint8_t attr;
struct _fcb x;
/*
char _fcb_drive;
char _fcb_name[8];
char _fcb_ext[3];
short _fcb_curblk;
short _fcb_recsize;
long _fcb_filsize;
short _fcb_date;
char _fcb_resv[10];
char _fcb_currec;
long _fcb_random;
*/
} __attribute__((packed)) xfcb;
int main(int argc, char *argv[])
{
union REGS r = {};
xfcb.sig = 0xff;
xfcb.attr = _A_VOLID;
xfcb.x._fcb_drive = 0;
/* it's very important that the disk has never had a label before */
memcpy(xfcb.x._fcb_name, "INITIAL ", 8); // create
memcpy(xfcb.x._fcb_ext, " ", 3);
r.x.ax = 0x1600;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On initial creation\n");
return 1;
}
r.x.ax = 0x1000; // close
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On initial close\n");
return 1;
}
memcpy(xfcb.x._fcb_name, "????????", 8); // delete with wildcard
memcpy(xfcb.x._fcb_ext, "???", 3);
r.x.ax = 0x1300;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On delete with wildcard\n");
return 1;
}
memcpy(xfcb.x._fcb_name, "RECREATI", 8); // recreation
memcpy(xfcb.x._fcb_ext, "ON ", 3);
r.x.ax = 0x1600;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On recreation\n");
return 1;
}
printf("PASS: Operation success\n");
return 0;
}
""")
results = self.runDosemu("testit.bat", config=config)
self.assertIn("PASS: Operation success", results)
self.assertRegex(results, "Volume in drive [Dd] is RECREATION")
self.assertNotIn("FAIL:", results)
def label_create_on_lfns(self):
testdir = self.mkworkdir('d')
names = [
"This Is A Long Filename.tXt",
"simple_but_long_filename.txt",
]
for n in names:
f2 = testdir / n
f2.write_text("HELLO THERE\n")
n3 = "LFNdirectory"
f3 = testdir / n3
f3.mkdir()
names += [n3,]
image = self.mkimage_vbr("12", lfn=True, cwd=testdir)
config = """\
$_hdimage = "dXXXXs/c:hdtype1 %s:partition +1"
$_floppy_a = ""
""" % image
self.mkfile("testit.bat", """\
d:
c:\\labclfns
rem end
""", newline="\r\n")
self.mkcom_with_ia16("labclfns", r"""
#include <dos.h>
#include <stdio.h>
#include <string.h>
struct {
uint8_t sig;
uint8_t pad[5];
uint8_t attr;
struct _fcb x;
/*
char _fcb_drive;
char _fcb_name[8];
char _fcb_ext[3];
short _fcb_curblk;
short _fcb_recsize;
long _fcb_filsize;
short _fcb_date;
char _fcb_resv[10];
char _fcb_currec;
long _fcb_random;
*/
} __attribute__((packed)) xfcb;
int main(int argc, char *argv[])
{
union REGS r = {};
xfcb.sig = 0xff;
xfcb.attr = _A_VOLID;
xfcb.x._fcb_drive = 0;
/* It's very important that the disk has no existing label */
/* We shouldn't error if the volume has any LFNs */
memcpy(xfcb.x._fcb_name, "INITIAL ", 8); // create
memcpy(xfcb.x._fcb_ext, " ", 3);
r.x.ax = 0x1600;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On initial creation\n");
return 1;
}
r.x.ax = 0x1000; // close
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On initial close\n");
return 1;
}
printf("INFO: Label was created successfully\n");
/* We should be able to delete the label without affecting the LFNs */
memcpy(xfcb.x._fcb_name, "????????", 8); // delete with wildcard
memcpy(xfcb.x._fcb_ext, "???", 3);
r.x.ax = 0x1300;
r.x.dx = FP_OFF(&xfcb);
intdos(&r, &r);
if (r.h.al != 0) {
printf("FAIL: On delete with wildcard\n");
return 1;
}
printf("INFO: Label was deleted successfully\n");
printf("PASS: Operation success\n");
return 0;
}
""")
results = self.runDosemu("testit.bat", config=config)
self.assertIn("PASS: Operation success", results)
self.assertNotIn("FAIL:", results)
# Check afterwards with mtools that each lfn still exists
args = ['mdir', '-i', str(self.imagedir / image)]
output = check_output(args, timeout=5, stderr=STDOUT).decode('ASCII')
for n in names:
self.assertIn(n, output)

View File

@@ -1,75 +0,0 @@
def lfn_voln_info(self, fstype):
testdir = self.mkworkdir('d')
self.mkfile("foo.dat", "some content", dname=testdir)
if fstype == "FAT16":
name = self.mkimage_vbr("16", cwd=testdir)
config = """$_hdimage = "dXXXXs/c:hdtype1 %s +1"\n""" % name
elif fstype == "FAT32":
name = self.mkimage_vbr("32", cwd=testdir)
config = """$_hdimage = "dXXXXs/c:hdtype1 %s +1"\n""" % name
elif fstype == "MFS":
config = """$_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d +1"\n"""
else:
raise ValueError
self.unTarOrSkip("TEST_DOSLFN.tar", [
("doslfn.com", "6fec9451489d81b16253a5340afdb955aa6136fb"),
("cp437uni.tbl", "4b2c5f7ef008e6826a75035822b65c5bb72e2ffe"),
("cp858uni.tbl", "4dc79f9b2e8d8f57187e94169eb9b7c79b32bb31"),
("cp866uni.tbl", "28d4dc1b9197fb03af9382674c3fa3321c0608b5"),
])
self.mkfile("testit.bat", """\
c:\\doslfn -f-
d:
c:\\lfnvinfo D:\\
rem end
""", newline="\r\n")
# compile sources
self.mkexe_with_djgpp("lfnvinfo", r"""
#include <dir.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
int main(int argc, char *argv[]) {
int max_file_len, max_path_len;
char fsystype[32];
unsigned rval;
if (argc < 1) {
printf("missing volume argument e.g. 'C:\\'\n");
return 1;
}
rval = _get_volume_info(argv[1], &max_file_len, &max_path_len, fsystype);
if (rval == 0 && errno) {
printf("ERRNO(%d)\r\n", errno);
return 2;
}
if (rval == _FILESYS_UNKNOWN) {
printf("FILESYS_UNKNOWN(%d)\r\n", errno);
return 3;
}
printf("FSTYPE(%s), FILELEN(%d), PATHLEN(%d), BITS(0x%04x)\r\n",
fsystype, max_file_len, max_path_len, rval);
return 0;
}
""")
results = self.runDosemu("testit.bat", config=config)
if fstype == "MFS":
self.assertIn("FSTYPE(MFS)", results)
elif fstype == "FAT16":
self.assertIn("FSTYPE(FAT)", results)
elif fstype == "FAT32":
self.assertIn("FSTYPE(FAT32)", results)

View File

@@ -1,144 +0,0 @@
import re
from os import statvfs
from subprocess import call, DEVNULL
def lfs_disk_info(self, fstype):
testdir = self.mkworkdir('d')
if fstype == 'MFS':
config="""$_hdimage = "dXXXXs/c:hdtype1 dXXXXs/d +1"\n"""
elif fstype == 'FAT32':
# Make a big file to use some space on the image
bigfile = testdir / 'bigfile.zro'
size = 104857600
call(["dd", "if=/dev/zero", "of=%s" % bigfile, "bs=%s" % size, "count=1"], stderr=DEVNULL)
name = self.mkimage_vbr("32", cwd=testdir)
config="""$_hdimage = "dXXXXs/c:hdtype1 %s +1"\n""" % name
else:
raise ValueError
self.mkfile("testit.bat", """\
d:
c:\\diskinfo D:\\
rem end
""", newline="\r\n")
# compile sources
self.mkexe_with_djgpp("diskinfo", r"""\
#include <stdio.h>
#include <stdint.h>
#include <string.h>
struct dinfo {
uint16_t size;
uint16_t version; // (0000h)
uint32_t spc;
uint32_t bps;
uint32_t avail_clusters;
uint32_t total_clusters;
uint32_t avail_sectors;
uint32_t total_sectors;
uint32_t avail_units;
uint32_t total_units;
char reserved[8];
};
#define MAXPATH 128
int main(int argc, char *argv[]) {
struct dinfo df;
uint8_t carry;
uint16_t ax;
int len;
if (argc < 2) {
printf("path argument missing e.g. 'C:\\'\n");
return 3;
}
len = strlen(argv[1]) + 1;
if (len > MAXPATH) {
printf("path argument too long\n");
return 2;
}
/*
AX = 7303h
DS:DX -> ASCIZ string for drive ("C:\" or "\\SERVER\Share")
ES:DI -> buffer for extended free space structure (see #01789)
CX = length of buffer for extended free space
Return:
CF clear if successful
ES:DI buffer filled
CF set on error
AX = error code
*/
asm volatile("stc\n"
"int $0x21\n"
"setc %0\n"
: "=r"(carry), "=a"(ax)
: "a"(0x7303), "d"(argv[1]), "D"(&df), "c"(sizeof(df))
: "cc", "memory");
if (carry) {
printf("Call failed (CARRY), AX = 0x%04x\n", ax);
return 1;
}
/* See if we have valid data */
if (df.size > sizeof(df)) {
printf("Call failed (Struct invalid), size = 0x%04x, version 0x%04x\n", df.size, df.version);
return 1;
}
printf("size 0x%04x\n", df.size);
printf("version 0x%04x\n", df.version);
printf("spc 0x%08lx\n", df.spc);
printf("bps 0x%08lx\n", df.bps);
printf("avail_clusters 0x%08lx\n", df.avail_clusters);
printf("total_clusters 0x%08lx\n", df.total_clusters);
printf("avail_sectors 0x%08lx\n", df.avail_sectors);
printf("total_sectors 0x%08lx\n", df.total_sectors);
printf("avail_units 0x%08lx\n", df.avail_units);
printf("total_units 0x%08lx\n", df.total_units);
printf("avail_bytes(%llu)\n",
(unsigned long long)df.spc * (unsigned long long)df.bps * (unsigned long long)df.avail_clusters);
printf("total_bytes(%llu)\n",
(unsigned long long)df.spc * (unsigned long long)df.bps * (unsigned long long)df.total_clusters);
return 0;
}
""")
results = self.runDosemu("testit.bat", config=config)
self.assertNotIn("Call failed", results)
t = re.search(r'total_bytes\((\d+)\)', results)
self.assertIsNotNone(t, "Unable to parse 'total_bytes'")
dfs_total = int(t.group(1))
a = re.search(r'avail_bytes\((\d+)\)', results)
self.assertIsNotNone(a, "Unable to parse 'avail_bytes'")
dfs_avail = int(a.group(1))
if fstype == 'MFS':
fsinfo = statvfs(self.workdir)
lfs_total = fsinfo.f_blocks * fsinfo.f_bsize
lfs_avail = fsinfo.f_bavail * fsinfo.f_bsize
else: # FAT32
lfs_total = (self.imagedir / name).stat().st_size
lfs_avail = lfs_total - size
# see if we are within 5% of the values expected
msg = "total dos %d, expected %d" % (dfs_total, lfs_total)
self.assertLessEqual(dfs_total, lfs_total * 1.05, msg)
self.assertGreaterEqual(dfs_total, lfs_total * 0.95, msg)
msg = "avail dos %d, expected %d" % (dfs_avail, lfs_avail)
self.assertLessEqual(dfs_avail, lfs_avail * 1.05, msg)
self.assertGreaterEqual(dfs_avail, lfs_avail * 0.95, msg)

View File

@@ -131,19 +131,11 @@ $_lredir_paths = "%s"
# Check the obvious fields
self.assertNotIn("Error: ", results)
r1 = re.compile(r'fsize_hi.*0x([0-9a-f]+)')
self.assertRegex(results, r1)
t = r1.search(results)
t = re.search(r'fsize_hi.*0x([0-9a-f]+)', results)
fsize_hi = int(t.group(1), 16)
r2 = re.compile(r'fsize_lo.*0x([0-9a-f]+)')
self.assertRegex(results, r2)
t = r2.search(results)
t = re.search(r'fsize_lo.*0x([0-9a-f]+)', results)
fsize_lo = int(t.group(1), 16)
r3 = re.compile(r'numlinks.*0x([0-9a-f]+)')
self.assertRegex(results, r3)
t = r3.search(results)
t = re.search(r'numlinks.*0x([0-9a-f]+)', results)
numlinks = int(t.group(1), 16)
self.assertEqual(fsize_hi, fsize >> 32)

View File

@@ -1,75 +0,0 @@
import re
from shutil import copy
from subprocess import check_call, check_output, CalledProcessError, DEVNULL, TimeoutExpired
TESTSUITE = "/usr/ia16-elf/libexec/libi86/tests/testsuite"
def libi86_create_items(testcase):
# Enumerate the tests
tests = []
try:
listing = check_output([TESTSUITE, '--list'])
except FileNotFoundError:
print('libi86-testsuite-ia16-elf not installed - skipping those\n')
return
for l in listing.split(b'\n'):
# b' 12: bios.h.at:83 _bios_equiplist'
t = re.search(r"\s*(\d+): (.+):\d+\s+([^']+)", str(l))
if t:
tests += [t.groups(),]
def create_test(test):
def do_test_libi86(self):
libi86_test_item(self, test[0])
docstring = """libi86 item % 3s %s""" % (test[0], test[2])
setattr(do_test_libi86, '__doc__', docstring)
setattr(do_test_libi86, 'libi86test', True)
return do_test_libi86
# Insert each test into the testcase
for test in tests:
name = 'test_libi86_item_%03d' % int(test[0])
setattr(testcase, name, create_test(test))
testcase.attrs += ['libi86test',]
def libi86_test_item(self, test):
self.mkfile("dosemu.conf", """\
$_hdimage = "dXXXXs/c:hdtype1 +1"
$_floppy_a = ""
""", dname=self.imagedir, mode="a")
build = self.imagedir / "libi86-test"
build.mkdir()
dosemu = self.topdir / "bin" / "dosemu"
options = '-f {0}/dosemu.conf -n --Fimagedir {0} -o {1}'.format(self.imagedir, self.logfiles['log'][0])
args = [
'--x-installcheck',
'--x-test-underlying',
'--x-with-dosemu=%s' % dosemu,
'--x-with-dosemu-options=%s' % options,
]
# Do just one
try:
starttime = self.utcnow()
check_call([TESTSUITE, *args, test[0]], cwd=build, timeout=60, stdout=DEVNULL, stderr=DEVNULL)
self.duration = self.utcnow() - starttime
except CalledProcessError:
raise self.failureException("Test error") from None
except TimeoutExpired:
raise self.failureException("Test timeout") from None
finally:
# The libi86 test suite has its own log file called 'testsuite.log',
# so we will present it as our usual expect log
logfile = build / "tests" / "testsuite.log"
if logfile.is_file():
copy(logfile, self.logfiles['xpt'][0])
self.logfiles['xpt'][1] = "testsuite.log"

View File

@@ -1,159 +0,0 @@
BATCHFILE = """\
c:\\%s
rem end
"""
CONFIG = """\
$_hdimage = "dXXXXs/c:hdtype1 +1"
$_floppy_a = ""
"""
def memory_dpmi_dpmi10_ldt(self):
# Note: Not sure if I need this
if 'FDPP' in self.version:
self.mkfile("userhook.sys", """DOS=HIGH\n""", newline="\r\n")
self.mkfile("testit.bat", BATCHFILE % 'dpmi1ldt primary', newline="\r\n")
self.mkexe_with_djgpp("dpmi1ldt", r"""
#include <dos.h>
#include <dpmi.h>
#include <process.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
int i, err;
uint32_t lim;
int primary = -1;
if (argc < 2) {
printf("FAIL: Missing argument (primary|secondary)\n");
return -2;
}
if (strcmp(argv[1], "primary") == 0)
primary = 1;
if (strcmp(argv[1], "secondary") == 0)
primary = 0;
if (primary < 0) {
printf("FAIL: Invalid argument (primary|secondary)\n");
return -2;
}
if (primary) {
unsigned short sel;
char selstr[16];
for (i = 0; i < 0x10; i++) {
sel = (i << 3) | 7;
err = __dpmi_allocate_specific_ldt_descriptor(sel);
if (err) {
printf("FAIL: %s: cannot allocate specific desc %#x\n", argv[1], i);
return -1;
}
lim = __dpmi_get_segment_limit(sel);
if (lim) {
printf("FAIL: %s: limit of desc %#x is %lx\n", argv[1], i, lim);
return -1;
}
err = __dpmi_set_segment_limit(sel, 0xfff);
if (err) {
printf("FAIL: %s: cannot set limit for %x\n", argv[1], i);
return -1;
}
}
printf("OKAY: %s: Allocated 16 LDT descriptors\n", argv[1]);
sel = __dpmi_allocate_ldt_descriptors(1);
if (sel == -1) {
printf("FAIL: cannot allocate LDT desc\n");
return -1;
}
err = __dpmi_set_segment_limit(sel, 0xfff);
if (err) {
printf("FAIL: cannot set segment limit\n");
return -1;
}
printf("OKAY: %s: Allocated descriptor at %#x\n", argv[1], sel);
sprintf(selstr, "%i", sel);
// Now start second copy
spawnlp(P_WAIT, argv[0], argv[0], "secondary", selstr, NULL);
for (i = 0; i < 0x10; i++) {
sel = (i << 3) | 7;
lim = __dpmi_get_segment_limit(sel);
if (lim != 0xfff) {
printf("FAIL: %s: limit of desc %#x is %lx\n", argv[1], i, lim);
return -1;
}
err = __dpmi_free_ldt_descriptor(sel);
if (err) {
printf("FAIL: %s: cannot free specific desc %#x\n", argv[1], i);
return -1;
}
}
printf("OKAY: %s: All descriptors checked and freed\n", argv[1]);
printf("Test 2 OK\n");
} else { // secondary
unsigned short sel = 0;
if (argc < 3) {
printf("FAIL: Missing argument (sel number)\n");
return -2;
}
sscanf(argv[2], "%hi", &sel);
if (!sel) {
printf("FAIL: %s: bad sel value %s\n", argv[1], argv[2]);
return -1;
}
lim = __dpmi_get_segment_limit(sel);
if (lim == 0) {
printf("FAIL: %s: sel %#x not allocated\n", argv[1], sel);
return -1;
}
if (lim != 0xfff) {
printf("FAIL: %s: limit of %#x is %lx\n", argv[1], sel, lim);
return -1;
}
printf("OKAY: %s: limit of %#x is %#lx\n", argv[1], sel, lim);
for (i = 0; i < 0x10; i++) {
sel = (i << 3) | 7;
err = __dpmi_allocate_specific_ldt_descriptor(sel);
if (err) {
printf("FAIL: %s: cannot allocate specific desc %#x\n", argv[1], i);
return -1;
}
lim = __dpmi_get_segment_limit(sel);
if (lim) {
printf("FAIL: %s: limit of desc %#x is %lx\n", argv[1], i, lim);
return -1;
}
err = __dpmi_free_ldt_descriptor(sel);
if (err) {
printf("FAIL: %s: cannot free specific desc %#x\n", argv[1], i);
return -1;
}
}
printf("OKAY: %s: Allocated and freed 16 LDT descriptors\n", argv[1]);
printf("Test 1 OK\n");
}
return 0;
}
""")
results = self.runDosemu("testit.bat", config=CONFIG)
self.assertIn("Test 1 OK", results)
self.assertIn("Test 2 OK", results)
self.assertNotIn("FAILURE:", results)

View File

@@ -1,158 +0,0 @@
import re
TTAR = "TEST_JAPHETH.tar"
TFILES = {
218: ("dpmihxrt218.exe", "65fda018f4422c39dbf36860aac2c537cfee466b"),
219: ("dpmihxrt219.exe", "4b0f60346244a5be9e3208fe63063bd26209d234"),
220: ("dpmihxrt220.exe", "c2a37cf9b8bab4fe911186821989fc49e6c0feb2"), # Pre2
}
def doit(self, version, switch, eofisok=False):
self.unTarOrSkip(TTAR, [TFILES[version],])
tfile = self.workdir / TFILES[version][0]
tfile.rename(self.workdir / "dpmi.exe")
self.mkfile("testit.bat", """\
c:\\dpmi %s
rem end
""" % switch, newline="\r\n")
return self.runDosemu("testit.bat", config="""\
$_hdimage = "dXXXXs/c:hdtype1 +1"
$_floppy_a = ""
$_dpmi = (0x40000)
""", timeout=60, eofisok=eofisok)
def bare(self):
results = doit(self, 218, "")
#Cpu is in V86-mode
#Int 15h, ax=e801h, extended memory: 8256 kB
#int 15h, ax=e820h, available memory at 000100000, size 8256 kB
#XMS v3.0 host found, largest free block: 8192 kB
#No VCPI host found
#DPMI v0.90 host found, cpu: 05, support of 32-bit clients: 1
#entry initial switch to protected-mode: F000:F500
#size task-specific memory: 230 paragraphs
#now in protected mode, client CS/SS/DS/FS/GS: A7/AF/AF/0/0
#Eflags=206, ES (=PSP): B7 (environment: BF, parent PSP segm: 431)
#GDTR: 17.A308100 IDTR: 7FF.A308200 LDTR: 0 TR: 0
#DPMI version flags: 5
#master/slave PICs base: 08/70
#state save protected-mode: 97:1, real-mode: F000:F514
#size state save buffer: 52 bytes
#raw jump to real-mode: 97:0, protected-mode: F000:F513
#largest free/lockable memory block (kB): 131004/131004
#free unlocked (=virtual) memory (kB): 131004
#total/free address space (kB): 32768/32768
#total/free physical memory (kB): 131072/131004
#Coprocessor status: 4D
#vendor: DOSEMU Version 2.0, version: 0.90
#capabilities: 78
#vendor 'MS-DOS' API entry: 97:130
#'MS-DOS' API, ax=100h (get LDT selector): E7
self.assertRegex(results, r"DPMI v\d.\d+ host found, cpu: \d+, support of 32-bit clients: 1")
self.assertRegex(results, r"DPMI version flags: 5")
self.assertRegex(results, r"vendor: DOSEMU2 Version 2.0, version: \d.\d+")
self.assertRegex(results, r"capabilities: \d+")
def _c(self):
results = doit(self, 218, "-c")
self.assertRegex(results, r"time.*CLI/STI: \d+ ms")
self.assertRegex(results, r"time.*interrupts via DPMI: \d+ ms")
def _d(self):
results = doit(self, 219, "-d")
t = re.search(r"(\d+) descriptors allocated", results)
self.assertIsNotNone(t, "Unable to parse number of allocated descriptors")
num = int(t.group(1))
self.assertGreater(num, 8000, results)
def _e(self):
# Dosemu2 shuts down with stack exhaustion so we have to allow EOF
results = doit(self, 219, "-e", eofisok=True)
# We want to achieve in the future at least the current level of nesting (192)
self.assertIn('ERROR: DPMI: too many nested realmode invocations, in_dpmi_rm_stack=192', results)
def _i(self):
results = doit(self, 218, "-i")
self.assertRegex(results, r"time.*IN 21: \d+ ms")
def _m(self):
results = doit(self, 218, "-m")
t = re.search(r"alloc largest mem block \(size=(\d+) kB\) returned handle [0-9a-fA-F]+, base \d+", results)
self.assertIsNotNone(t, "Unable to parse memory block size")
size = int(t.group(1))
self.assertGreater(size, 128000, results)
def _r(self):
results = doit(self, 218, "-r")
self.assertRegex(results, r"time.*INT 69h: \d+ ms")
self.assertRegex(results, r"time.*INT 31h, AX=0300h \(Sim INT 69h\): \d+ ms")
self.assertRegex(results, r"time.*real-mode callback: \d+ ms")
self.assertRegex(results, r"time.*raw mode switches PM->RM->PM: \d+ ms")
def _t(self):
results = doit(self, 218, "-t")
#C:\>c:\dpmi -t
#allocated rm callback FF10:214, rmcs=AF:20E4
#calling rm proc [53A:8B6], rm cx=1
# inside rm proc, ss:sp=7A8:1FC, cx=1
# calling rm callback FF10:214
# inside rm callback, ss:esp=9F:EFF4, ds:esi=F7:1FC
# es:edi=AF:20E4, rm ss:sp=7A8:1FC, rm cx=1
# calling rm proc [53A:8B6]
# inside rm proc, ss:sp=7A8:1F8, cx=2
# calling rm callback FF10:214
# inside rm callback, ss:esp=9F:EFE0, ds:esi=F7:1F8
# es:edi=AF:20E4, rm ss:sp=7A8:1F8, rm cx=2
# exiting
# back in rm proc, ss:sp=7A8:1F8; exiting
# back in rm callback, rm ss:sp=7A8:1FC, rm cx=2; exiting
# back in rm proc, ss:sp=7A8:1FC; exiting
#back in protected-mode, rm ss:sp=7A8:200, rm cx=2
self.assertRegex(results, re.compile(r"^allocated rm callback", re.MULTILINE))
self.assertRegex(results, re.compile(r"^ inside rm proc", re.MULTILINE))
self.assertRegex(results, re.compile(r"^ inside rm callback", re.MULTILINE))
self.assertRegex(results, re.compile(r"^ inside rm proc", re.MULTILINE))
self.assertRegex(results, re.compile(r"^ inside rm callback", re.MULTILINE))
self.assertRegex(results, re.compile(r"^ back in rm proc", re.MULTILINE))
self.assertRegex(results, re.compile(r"^ back in rm callback", re.MULTILINE))
self.assertRegex(results, re.compile(r"^ back in rm proc", re.MULTILINE))
self.assertRegex(results, re.compile(r"^back in protected-mode", re.MULTILINE))
def _z(self):
results = doit(self, 220, "-z")
t = re.search(r"DPMI: launch succeeded, int 21h calls: (\d+)", results)
self.assertIsNotNone(t, "Unable to parse number of int 21h calls")
num = int(t.group(1))
self.assertGreater(num, 800, results)
def memory_dpmi_japheth(self, switch):
f = {
'': bare,
'-c': _c,
'-d': _d,
'-e': _e,
'-i': _i,
'-m': _m,
'-r': _r,
'-t': _t,
'-z': _z,
}
f[switch](self)

View File

@@ -1,89 +0,0 @@
import re
def memory_dpmi_leak_check(self, tipo):
self.mkfile("testit.bat", """\
c:\\dpmileak TEST0 {0}
c:\\dpmileak TEST1 {0}
c:\\dpmileak TEST2 {0}
c:\\dpmileak TEST3 {0}
c:\\dpmileak TEST4 {0}
c:\\dpmileak TEST5 {0}
c:\\dpmileak TEST6 {0}
c:\\dpmileak TEST7 {0}
c:\\dpmileak TEST8 {0}
c:\\dpmileak TEST9 {0}
rem end
""".format(tipo), newline="\r\n")
self.mkexe_with_djgpp("dpmileak", r"""
#include <dos.h>
#include <dpmi.h>
#include <process.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
__dpmi_meminfo info = {};
int dofree = 1;
if (argc < 2) {
printf("FAIL: Missing argument IDSTRING (normal|nofree)\n");
return -2;
}
if (argc > 2 && strcmp(argv[2], "nofree") == 0)
dofree = 0;
info.size = 0x20000;
if (__dpmi_allocate_memory(&info) == -1) {
printf("FAIL: (%s) DPMI allocation failed\n", argv[1]);
return -1;
}
printf("INFO: (%s) DPMI allocation info: HNDL=%08lx, SIZE=%08lx, ADDR=%08lx\n",
argv[1], info.handle, info.size, info.address);
if (dofree) {
if (__dpmi_free_memory(info.handle) == -1) {
printf("FAIL: (%s) DPMI free failed\n", argv[1]);
return -1;
}
printf("INFO: (%s) Successful Free\n", argv[1]);
} else {
printf("INFO: (%s) Skipping Free\n", argv[1]);
}
printf("DONE: (%s)", argv[1]);
return 0;
}
""")
results = self.runDosemu("testit.bat", config="""\
$_hdimage = "dXXXXs/c:hdtype1 +1"
$_floppy_a = ""
""")
# INFO: (TEST0) DPMI allocation info: HNDL=00000012, SIZE=00020000, ADDR=21199000
m = re.search(r'\(TEST0\).*HNDL=([\da-f]+), SIZE=([\da-f]+), ADDR=([\da-f]+)', results)
self.assertIsNotNone(m, results)
FMT = r'(?m)^INFO: \(%s\).*, SIZE=%s, ADDR=%s[\r\n]+'
self.assertRegex(results, FMT % ('TEST1', m.group(2), m.group(3)))
self.assertRegex(results, FMT % ('TEST2', m.group(2), m.group(3)))
self.assertRegex(results, FMT % ('TEST3', m.group(2), m.group(3)))
self.assertRegex(results, FMT % ('TEST4', m.group(2), m.group(3)))
self.assertRegex(results, FMT % ('TEST5', m.group(2), m.group(3)))
self.assertRegex(results, FMT % ('TEST6', m.group(2), m.group(3)))
self.assertRegex(results, FMT % ('TEST7', m.group(2), m.group(3)))
self.assertRegex(results, FMT % ('TEST8', m.group(2), m.group(3)))
self.assertRegex(results, FMT % ('TEST9', m.group(2), m.group(3)))
self.assertNotIn("FAIL:", results)

View File

@@ -1,88 +0,0 @@
import re
def memory_dpmi_leak_check_dos(self, tipo):
self.mkfile("testit.bat", """\
c:\\dpmileak TEST0 {0}
c:\\dpmileak TEST1 {0}
c:\\dpmileak TEST2 {0}
c:\\dpmileak TEST3 {0}
c:\\dpmileak TEST4 {0}
c:\\dpmileak TEST5 {0}
c:\\dpmileak TEST6 {0}
c:\\dpmileak TEST7 {0}
c:\\dpmileak TEST8 {0}
c:\\dpmileak TEST9 {0}
rem end
""".format(tipo), newline="\r\n")
self.mkexe_with_djgpp("dpmileak", r"""
#include <dos.h>
#include <dpmi.h>
#include <process.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdint.h>
int main(int argc, char *argv[])
{
int selector, segment;
int dofree = 1;
if (argc < 2) {
printf("FAIL: Missing argument IDSTRING (normal|nofree)\n");
return -2;
}
if (argc > 2 && strcmp(argv[2], "nofree") == 0)
dofree = 0;
segment = __dpmi_allocate_dos_memory(4096, &selector);
if (segment == -1) {
printf("FAIL: (%s) DPMI allocation (DOS) failed\n", argv[1]);
return -1;
}
printf("INFO: (%s) DPMI allocation (DOS) info: SEGMENT=%04x, SELECTOR=%04x\n",
argv[1], segment, selector);
if (dofree) {
if (__dpmi_free_dos_memory(selector) == -1) {
printf("FAIL: (%s) DPMI free (DOS) failed\n", argv[1]);
return -1;
}
printf("INFO: (%s) Successful Free (DOS)\n", argv[1]);
} else {
printf("INFO: (%s) Skipping Free (DOS)\n", argv[1]);
}
printf("DONE: (%s)", argv[1]);
return 0;
}
""")
results = self.runDosemu("testit.bat", config="""\
$_hdimage = "dXXXXs/c:hdtype1 +1"
$_floppy_a = ""
""")
# INFO: (TEST0) DPMI allocation (DOS) info: SEGMENT=04c5, SELECTOR=01bf
m = re.search(r'\(TEST0\).*info: SEGMENT=([\da-f]+), SELECTOR=([\da-f]+)', results)
self.assertIsNotNone(m, results)
FMT = r'(?m)^INFO: \(%s\).*info: SEGMENT=%s, SELECTOR=%s[\r\n]+'
self.assertRegex(results, FMT % ('TEST1', m.group(1), m.group(2)))
self.assertRegex(results, FMT % ('TEST2', m.group(1), m.group(2)))
self.assertRegex(results, FMT % ('TEST3', m.group(1), m.group(2)))
self.assertRegex(results, FMT % ('TEST4', m.group(1), m.group(2)))
self.assertRegex(results, FMT % ('TEST5', m.group(1), m.group(2)))
self.assertRegex(results, FMT % ('TEST6', m.group(1), m.group(2)))
self.assertRegex(results, FMT % ('TEST7', m.group(1), m.group(2)))
self.assertRegex(results, FMT % ('TEST8', m.group(1), m.group(2)))
self.assertRegex(results, FMT % ('TEST9', m.group(1), m.group(2)))
self.assertNotIn("FAIL:", results)

View File

@@ -1,601 +0,0 @@
BATCHFILE = """\
c:\\%s
rem end
"""
CONFIG = """\
$_hdimage = "dXXXXs/c:hdtype1 +1"
$_floppy_a = ""
"""
def memory_hma_freespace(self):
if 'FDPP' in self.version:
self.mkfile("userhook.sys", """DOS=HIGH\n""", newline="\r\n")
self.mkfile("testit.bat", BATCHFILE % 'hmaspace', newline="\r\n")
self.mkcom_with_ia16("hmaspace", r"""
#include <i86.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
union REGS r = {};
struct SREGS rs;
int ret = 0;
r.x.ax = 0x4a01; // get hma free space
int86x(0x2f, &r, &r, &rs);
if (r.x.bx == 0) {
printf("INFO: DOS not using HMA(BX==0)\n");
ret += 1;
}
if (rs.es == 0xffff && r.x.di == 0xffff) {
printf("INFO: DOS not using HMA(ES:DI==FFFF:FFFF)\n");
ret += 1;
}
if (ret != 0) {
printf("FAIL: No HMA available\n");
return ret;
}
printf("INFO: HMA free space == 0x%04x\n", r.x.bx);
printf("INFO: HMA area at %04X:%04X\n", rs.es, r.x.di);
printf("PASS: HMA available\n");
return 0;
}
""")
results = self.runDosemu("testit.bat", config=CONFIG)
self.assertIn("PASS:", results)
def memory_hma_alloc(self):
if 'FDPP' in self.version:
self.mkfile("userhook.sys", """DOS=HIGH\n""", newline="\r\n")
self.mkfile("testit.bat", BATCHFILE % 'hmaalloc', newline="\r\n")
self.mkcom_with_ia16("hmaalloc", r"""
#include <i86.h>
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
union REGS r = {};
struct SREGS rs;
int ret = 0;
r.x.ax = 0x4a02; // get hma memory block
r.x.bx = 35; // alloc 35 bytes, should get rounded up to 48
int86x(0x2f, &r, &r, &rs);
printf("INFO: HMA size returned %d\n", r.x.bx);
printf("INFO: HMA block allocated at %04X:%04X\n", rs.es, r.x.di);
if (r.x.bx != 48) {
printf("WARN: HMA returned size unexpected\n");
ret += 1;
}
if (rs.es != 0xffff) {
printf("WARN: HMA block allocated in wrong segment\n");
ret += 1;
}
if (ret != 0) {
printf("FAIL: Test failed\n");
return ret;
}
printf("PASS: HMA allocation successful\n");
return 0;
}
""")
results = self.runDosemu("testit.bat", config=CONFIG)
self.assertIn("PASS:", results)
def memory_hma_alloc3(self):
if 'FDPP' in self.version:
self.mkfile("userhook.sys", """DOS=HIGH\n""", newline="\r\n")
self.mkfile("testit.bat", BATCHFILE % 'hmaalloc', newline="\r\n")
self.mkcom_with_ia16("hmaalloc", r"""
#include <i86.h>
#include <stdio.h>
#include <string.h>
struct HMCB {
uint8_t signature[2]; // "MS"
uint16_t owner; // 0000=free, 0001=DOS, FF33=IO.SYS, FFFF=MSDOS.SYS
uint16_t size; // bytes not including this header
uint16_t next; // offset of next memory block in segment FFFFh, or 0000h if last
uint8_t reserved[8]; // unused (explicitly set to 0 for MS-DOS 7.10)
};
/*
Windows95 - DOS KERNEL - (DE)ALLOCATE HMA MEMORY BLOCK
AX = 4A03h
CX = segment of block's owner???
DL = subfunction
00h allocate block
BX = number of bytes
Return:
DI=FFFFh if unable to allocate
ES:DI -> allocated block
// We do get the allocated size in BX, RBIL misses this
01h resize block // Seemingly can grow as well as shrink
ES:DI -> previously-allocated block
BX = new size in bytes
Return:
DI=FFFFh if unable to allocate
ES:DI -> reallocated block
// Maybe we get the reallocated size in BX
Win95 FE & SE never seem to free the initial block after creating the
replacement. In addition, subsequent frees of the replacement block
fail.
02h free block
ES:DI -> block to be freed
Return:
Nothing, but checking the ID in the requested block can indicate
whether the block was freed.
*/
int main(int argc, char *argv[])
{
union REGS r = {};
struct SREGS rs;
int ret;
struct HMCB hmcb;
uint16_t hma_seg, hma_off;
// Alloc subfunction
ret = 0;
r.x.ax = 0x4a03; // hma alloc/realloc/free memory block
r.x.bx = 35; // alloc 35 bytes, should get rounded up to 48
r.x.cx = __libi86_get_cs(); // segment of block's owner
r.h.dl = 0; // subfunction 0 - alloc
printf("INFO: Int2f/4a03, dl=0 alloc\n");
int86x(0x2f, &r, &r, &rs);
printf("INFO: HMA size returned %d\n", r.x.bx);
printf("INFO: HMA block allocated at %04X:%04X\n", rs.es, r.x.di);
// Copy back to near structure to make printfs easier
memset(&hmcb, 0, sizeof(hmcb));
_fmemcpy(&hmcb, MK_FP(rs.es, r.x.di - 0x10), sizeof(hmcb));
printf("INFO: \"%c%c\" // signature\n", hmcb.signature[0], hmcb.signature[1]);
printf("INFO: %04X // owner, our CS = %04X\n", hmcb.owner, __libi86_get_cs());
printf("INFO: %04X // size (hex bytes)\n", hmcb.size);
printf("INFO: %04X // offset to next HMA block\n", hmcb.next);
if (r.x.di == 0xffff) {
printf("WARN: HMA returned offset indicates failure (DI == 0xffff)\n");
ret += 1;
}
if (r.x.bx != 48) {
printf("WARN: HMA returned size unexpected (BX == %d)\n", r.x.bx);
ret += 1;
}
if (r.x.bx != hmcb.size) {
printf("WARN: hmcb.size != HMA returned size (%d != %d)\n", hmcb.size, r.x.bx);
ret += 1;
}
if (ret != 0) {
printf("FAIL: Alloc test failed\n");
return ret;
}
hma_seg = rs.es;
hma_off = r.x.di;
printf("\n");
#if 0 // Disable resize tests as the function doesn't seem to work on Win95 SE
// allocating multiple blocks and preventing final free.
// Realloc subfunction (shrink block)
ret = 0;
r.x.ax = 0x4a03; // hma alloc/realloc/free memory block
r.x.bx = 29; // realloc 29 bytes, should get rounded up to 32
r.x.cx = __libi86_get_cs(); // segment of block's owner
r.h.dl = 1; // subfunction 1 - realloc
rs.es = hma_seg; // old block seg:off
r.x.di = hma_off;
printf("INFO: Int2f/4a03, dl=1 realloc (shrink)(%04X:%04X)\n", rs.es, r.x.di);
int86x(0x2f, &r, &r, &rs);
printf("INFO: HMA size returned %d\n", r.x.bx);
printf("INFO: HMA block reallocated at %04X:%04X\n", rs.es, r.x.di);
// Copy back to near structure to make printfs easier
memset(&hmcb, 0, sizeof(hmcb));
_fmemcpy(&hmcb, MK_FP(rs.es, r.x.di - 0x10), sizeof(hmcb));
printf("INFO: \"%c%c\" // signature\n", hmcb.signature[0], hmcb.signature[1]);
printf("INFO: %04X // owner, our CS = %04X\n", hmcb.owner, __libi86_get_cs());
printf("INFO: %04X // size (hex bytes)\n", hmcb.size);
printf("INFO: %04X // offset to next HMA block\n", hmcb.next);
if (r.x.di == 0xffff) {
printf("WARN: HMA returned offset indicates failure (DI == 0xffff)\n");
ret += 1;
}
if (r.x.bx != 32) {
printf("WARN: HMA returned size unexpected (BX == %d)\n", r.x.bx);
ret += 1;
}
if (r.x.bx != hmcb.size) {
printf("WARN: hmcb.size != HMA returned size (%d != %d)\n", hmcb.size, r.x.bx);
ret += 1;
}
if (ret != 0) {
printf("FAIL: Realloc(shrink) test failed\n");
return ret;
}
hma_seg = rs.es;
hma_off = r.x.di;
printf("\n");
// Realloc subfunction (grow block)
ret = 0;
r.x.ax = 0x4a03; // hma alloc/realloc/free memory block
r.x.bx = 65; // realloc 65 bytes, should get rounded up to 80
r.x.cx = __libi86_get_cs(); // segment of block's owner
r.h.dl = 1; // subfunction 1 - realloc
rs.es = hma_seg; // old block seg:off
r.x.di = hma_off;
printf("INFO: Int2f/4a03, dl=1 realloc (grow)(%04X:%04X)\n", rs.es, r.x.di);
int86x(0x2f, &r, &r, &rs);
printf("INFO: HMA size returned %d\n", r.x.bx);
printf("INFO: HMA block reallocated at %04X:%04X\n", rs.es, r.x.di);
// Copy back to near structure to make printfs easier
memset(&hmcb, 0, sizeof(hmcb));
_fmemcpy(&hmcb, MK_FP(rs.es, r.x.di - 0x10), sizeof(hmcb));
printf("INFO: \"%c%c\" // signature\n", hmcb.signature[0], hmcb.signature[1]);
printf("INFO: %04X // owner, our CS = %04X\n", hmcb.owner, __libi86_get_cs());
printf("INFO: %04X // size (hex bytes)\n", hmcb.size);
printf("INFO: %04X // offset to next HMA block\n", hmcb.next);
if (r.x.di == 0xffff) {
printf("WARN: HMA returned offset indicates failure (DI == 0xffff)\n");
ret += 1;
}
if (r.x.bx != 80) {
printf("WARN: HMA returned size unexpected (BX == %d)\n", r.x.bx);
ret += 1;
}
if (r.x.bx != hmcb.size) {
printf("WARN: hmcb.size != HMA returned size (%d != %d)\n", hmcb.size, r.x.bx);
ret += 1;
}
if (ret != 0) {
printf("FAIL: Realloc(grow) test failed\n");
return ret;
}
hma_seg = rs.es;
hma_off = r.x.di;
printf("\n");
#endif
// Free block subfunction
ret = 0;
r.x.ax = 0x4a03; // hma alloc/realloc/free memory block
r.x.cx = __libi86_get_cs(); // segment of block's owner
r.h.dl = 2; // subfunction 2 - free
rs.es = hma_seg; // old block seg:off
r.x.di = hma_off;
printf("INFO: Int2f/4a03, dl=2 free (%04X:%04X)\n", rs.es, r.x.di);
int86x(0x2f, &r, &r, &rs);
// Free doesn't return anything to indicate success, so we have to check the
// requested block to see if it's still marked as ours
// Copy back to near structure to make access easier
memset(&hmcb, 0, sizeof(hmcb));
_fmemcpy(&hmcb, MK_FP(rs.es, r.x.di - 0x10), sizeof(hmcb));
if (hmcb.signature[0] == 'M' && hmcb.signature[1] == 'S' &&
hmcb.owner == __libi86_get_cs()) {
printf("WARN: Freed block still marked as ours\n");
ret += 1;
}
if (ret != 0) {
printf("FAIL: Free test failed\n");
return ret;
}
printf("\n");
printf("PASS: HMA alloc/realloc/free successful\n");
return 0;
}
""")
results = self.runDosemu("testit.bat", config=CONFIG)
self.assertIn("PASS:", results)
def memory_hma_chain(self):
if 'FDPP' in self.version:
self.mkfile("userhook.sys", """DOS=HIGH\n""", newline="\r\n")
self.mkfile("testit.bat", BATCHFILE % 'hmachain', newline="\r\n")
self.mkcom_with_ia16("hmachain", r"""
#include <i86.h>
#include <stdio.h>
#include <string.h>
struct HMCB {
uint8_t signature[2]; // "MS"
uint16_t owner; // 0000=free, 0001=DOS, FF33=IO.SYS, FFFF=MSDOS.SYS
uint16_t size; // bytes not including this header
uint16_t next; // offset of next memory block in segment FFFFh, or 0000h if last
uint8_t reserved[8]; // unused (explicitly set to 0 for MS-DOS 7.10)
};
/*
INT 2F U - Windows95 - DOS KERNEL - GET START OF HMA MEMORY CHAIN
AX = 4A04h
Return: AX = 0000h if function supported
ES:DI -> first HMA memory control block (see #02800)
*/
int main(int argc, char *argv[])
{
union REGS r = {};
struct SREGS rs;
int ret;
struct HMCB hmcb;
// Alloc subfunction
ret = 0;
r.x.ax = 0x4a04; // get start of hma chain
printf("INFO: Int2f/4a04\n");
int86x(0x2f, &r, &r, &rs);
if (r.x.ax != 0) {
printf("WARN: HMA get chain returned (0x%04x), unsupported\n", r.x.ax);
ret += 1;
} else {
printf("INFO: HMA head at %04X:%04X\n", rs.es, r.x.di);
// Copy back to near structure to make printfs easier
memset(&hmcb, 0, sizeof(hmcb));
_fmemcpy(&hmcb, MK_FP(rs.es, r.x.di), sizeof(hmcb));
printf("INFO: \"%c%c\" // signature\n", hmcb.signature[0], hmcb.signature[1]);
printf("INFO: %04X // owner\n", hmcb.owner);
printf("INFO: %04X // size (hex bytes)\n", hmcb.size);
printf("INFO: %04X // offset to next HMA block\n", hmcb.next);
if (hmcb.signature[0] != 'M' || hmcb.signature[1] != 'S') {
printf("WARN: HMA head signature incorrect\n");
ret += 1;
}
}
if (ret != 0) {
printf("FAIL: HMA get chain failed\n");
return ret;
}
printf("PASS: HMA get chain successful\n");
return 0;
}
""")
results = self.runDosemu("testit.bat", config=CONFIG)
self.assertIn("PASS:", results)
def memory_hma_a20(self):
if 'FDPP' in self.version:
self.mkfile("userhook.sys", """DOS=HIGH\n""", newline="\r\n")
self.mkfile("testit.bat", BATCHFILE % 'hmaa20', newline="\r\n")
self.mkcom_with_ia16("hmaa20", r"""
#include <i86.h>
#include <stdio.h>
#include <string.h>
#define TSTRING "HELLO THERE"
int main(int argc, char *argv[])
{
union REGS r = {};
struct SREGS rs;
char testbuf[sizeof(TSTRING)];
char savebuf[sizeof(TSTRING)];
char __far *hma_location;
char __far *cnv_location;
int ret = 0;
int a20;
int res1, res2, val1, val2;
r.x.ax = 0x4a02; // get hma memory block
r.x.bx = 35; // alloc 35 bytes, should get rounded up to 48
int86x(0x2f, &r, &r, &rs);
printf("INFO: HMA size returned %d\n", r.x.bx);
printf("INFO: HMA block allocated at %04X:%04X\n", rs.es, r.x.di);
if (rs.es != 0xffff) {
printf("WARN: HMA block allocated in wrong segment\n");
ret += 1;
}
// Note: wrapped address will always be in first segment
hma_location = MK_FP(rs.es, r.x.di);
cnv_location = MK_FP(0x0000, ((rs.es << 4) + r.x.di) & 0xffff);
_disable();
// Get A20 status
r.x.ax = 0x2402;
r.x.cflag = 1;
int86x(0x15, &r, &r, &rs);
if (!r.x.cflag) {
a20 = r.h.al;
} else {
a20 = 1; // default to on
}
res1 = r.x.cflag;
val1 = r.h.al;
val2 = r.h.ah;
// Save memory
_fmemcpy(savebuf, cnv_location, sizeof(TSTRING));
// Write to HMA memory
_fmemcpy(hma_location, TSTRING, sizeof(TSTRING));
// Read from the wrapped address
_fmemcpy(testbuf, cnv_location, sizeof(TSTRING));
// Restore corrupted memory as soon as possible
_fmemcpy(cnv_location, savebuf, sizeof(TSTRING));
_enable();
if (!res1) {
printf("INFO: A20 is initially %s\n", val1 == 0 ? "disabled" : "enabled");
} else {
printf("WARN: A20 status could not be determined (0x%02x)\n", val2);
ret += 1;
}
// Compare to make sure we are not writing in the wrong place
if (memcmp(testbuf, TSTRING, sizeof(TSTRING)) == 0) {
printf("WARN: Wrapping is evident\n");
ret += 1;
} else {
printf("INFO: Wrapping is not evident\n");
}
_disable();
// Disable the A20 to enable the wrapping of memory
r.x.ax = 0x2400;
r.x.cflag = 1;
int86x(0x15, &r, &r, &rs);
res1 = r.x.cflag;
if (res1)
val1 = r.h.ah;
// Save memory
_fmemcpy(savebuf, cnv_location, sizeof(TSTRING));
// Write to HMA memory
_fmemcpy(hma_location, TSTRING, sizeof(TSTRING));
// Read from the wrapped address
_fmemcpy(testbuf, cnv_location, sizeof(TSTRING));
// Restore corrupted memory as soon as possible
_fmemcpy(cnv_location, savebuf, sizeof(TSTRING));
// Maybe reenable the A20 to return to normal
if (a20) {
r.x.ax = 0x2401;
r.x.cflag = 1;
int86x(0x15, &r, &r, &rs);
res2 = r.x.cflag;
val2 = r.h.ah;
}
_enable();
if (!res1) {
printf("INFO: A20 successfully disabled\n");
} else {
printf("WARN: A20 could not be disabled (0x%02x)\n", val1);
ret += 1;
}
if (a20)
if (!res2) {
printf("INFO: A20 successfully reenabled\n");
} else {
printf("WARN: A20 could not be reenabled\n (0x%02x)\n", val2);
ret += 1;
}
// Compare
if (memcmp(testbuf, TSTRING, sizeof(TSTRING)) == 0) {
printf("INFO: Wrapping is evident and expected\n");
} else {
printf("WARN: Wrapping is not evident\n");
ret += 1;
}
if (ret != 0) {
printf("FAIL: Test failed\n");
return ret;
}
printf("PASS: HMA allocation successful\n");
return 0;
}
""")
results = self.runDosemu("testit.bat", config=CONFIG)
self.assertIn("PASS:", results)

View File

@@ -1,164 +0,0 @@
BATCHFILE = """\
c:\\%s
rem end
"""
CONFIG = """\
$_hdimage = "dXXXXs/c:hdtype1 +1"
$_floppy_a = ""
"""
def memory_uma_strategy(self):
self.mkfile("testit.bat", BATCHFILE % 'umastrat', newline="\r\n")
self.mkexe_with_djgpp("umastrat", r"""\
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <dpmi.h>
#include <sys/movedata.h>
#include <sys/segments.h>
#include <stubinfo.h>
typedef unsigned FAR_PTR;
struct PSP {
unsigned short opint20; /* 0x00 */
unsigned short memend_frame; /* 0x02 */
unsigned char dos_reserved4; /* 0x04 */
unsigned char cpm_function_entry[0xa-0x5]; /* 0x05 */
FAR_PTR int22_copy; /* 0x0a */
FAR_PTR int23_copy; /* 0x0e */
FAR_PTR int24_copy; /* 0x12 */
unsigned short parent_psp; /* 0x16 */
unsigned char file_handles[20]; /* 0x18 */
unsigned short envir_frame; /* 0x2c */
FAR_PTR system_stack; /* 0x2e */
unsigned short max_open_files; /* 0x32 */
FAR_PTR file_handles_ptr; /* 0x34 */
unsigned char dos_reserved38[0x50-0x38]; /* 0x38 */
unsigned char high_language_dos_call[0x53-0x50]; /* 0x50 */
unsigned char dos_reserved53[0x5c-0x53]; /* 0x53 */
unsigned char FCB1[0x6c-0x5c]; /* 0x5c */
unsigned char FCB2[0x80-0x6c]; /* 0x6c */
unsigned char cmdline_len; /* 0x80 */
char cmdline[0x100-0x81]; /* 0x81 */
} __attribute__((packed));
static struct PSP psp; // make it static to be %ds-addresable
int main()
{
__dpmi_regs r = {};
int err;
unsigned long psp_addr;
unsigned short psp_seg;
int alloced, want_alloc;
int ret = 0;
err = __dpmi_get_segment_base_address(_stubinfo->psp_selector, &psp_addr);
if (err || (psp_addr & 0xf) || psp_addr >= 0x110000) {
printf("FAIL: get psp failed\n");
exit(1);
}
psp_seg = psp_addr >> 4;
printf("INFO: PSP at %x\n", psp_seg);
if (psp_seg > 0xa000) {
printf("FAIL: test loaded high, BAD. Use SHELL_LOADHIGH_DEFAULT=0 dosemu arg\n");
exit(1);
}
movedata(_stubinfo->psp_selector, 0, _my_ds(), (uintptr_t)&psp, sizeof(psp));
printf("INFO: mem end: %x\n", psp.memend_frame);
if (psp.memend_frame > 0xa000) {
printf("FAIL: too many memory allocated, FAILURE\n");
exit(1);
}
r.h.ah = 0x48;
r.x.bx = 1;
__dpmi_int(0x21, &r); /* allocate one-paragraph block */
if ((r.x.flags & 1)) {
printf("FAIL: alloc failed\n");
exit(1);
}
printf("INFO: alloc at %x\n", r.x.ax);
if (r.x.ax > 0xa000) {
printf("FAIL: initial alloc at UMB, FAILURE!\n");
exit(1);
}
r.x.es = r.x.ax;
r.h.ah = 0x49;
__dpmi_int(0x21, &r); /* free block */
if ((r.x.flags & 1)) {
printf("FAIL: free failed\n");
exit(1);
}
/* try UMB alloc */
r.x.ax = 0x5801;
r.x.bx = 0x80;
__dpmi_int(0x21, &r);
#if 1
r.x.ax = 0x5803;
r.x.bx = 1;
__dpmi_int(0x21, &r);
#endif
r.h.ah = 0x48;
r.x.bx = 1;
__dpmi_int(0x21, &r); /* allocate one-paragraph block */
if ((r.x.flags & 1)) {
printf("FAIL: alloc failed\n");
exit(1);
}
printf("INFO: alloc at %x\n", r.x.ax);
if (r.x.ax < 0xa000) {
printf("FAIL: alloc at UMB FAILED\n");
ret++;
// exit(1);
} else
printf("INFO: alloc at UMB OK\n");
r.x.es = r.x.ax;
r.h.ah = 0x49;
__dpmi_int(0x21, &r); /* free block */
if ((r.x.flags & 1)) {
printf("FAIL: free failed\n");
ret++;
// exit(1);
}
/* try large low alloc */
r.x.ax = 0x5801;
r.x.bx = 0;
__dpmi_int(0x21, &r);
want_alloc = 0xe000;
alloced = 0;
while (alloced < want_alloc) {
r.h.ah = 0x48;
r.x.bx = 0x100;
__dpmi_int(0x21, &r);
if ((r.x.flags & 1))
break;
alloced += 0x100;
}
printf("INFO: allocated %i of %i\n", alloced << 4, want_alloc << 4);
if (alloced < 0xa000) {
printf("FAIL: UMB not allocated, FAILURE\n");
ret++;
}
if (ret == 0)
printf("PASS: Done\n");
else
printf("FAIL: One or more non-fatal errors occurred\n");
return ret;
}
""")
results = self.runDosemu("testit.bat", config=CONFIG)
self.assertIn("PASS:", results)
self.assertNotIn("FAIL:", results)

View File

@@ -1,216 +0,0 @@
BATCHFILE = """\
c:\\%s
rem end
"""
CONFIG = """\
$_hdimage = "dXXXXs/c:hdtype1 +1"
$_floppy_a = ""
"""
def memory_xms(self):
# Note: Not sure if I need this
if 'FDPP' in self.version:
self.mkfile("userhook.sys", """DOS=HIGH\n""", newline="\r\n")
self.mkfile("testit.bat", BATCHFILE % 'xmstest', newline="\r\n")
self.mkexe_with_djgpp("xmstest", r"""
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <dpmi.h>
#include <sys/nearptr.h>
#ifndef PAGE_SIZE
#define PAGE_SIZE 4096
#endif
struct __attribute__ ((__packed__)) EMM {
unsigned int Length;
unsigned short SourceHandle;
unsigned int SourceOffset;
unsigned short DestHandle;
unsigned int DestOffset;
};
static __dpmi_paddr xms;
static struct EMM e;
static int call_xms(unsigned fn, unsigned arg, unsigned *ret)
{
int rc, err;
asm volatile("lcall *%[x]\n"
: "=a"(rc), "=d"(*ret), "=b"(err)
: [x]"m"(xms), "a"(fn << 8), "d"(arg)
: "cc", "memory");
if (!rc)
printf("xms error %x\n", err & 0xff);
return rc;
}
static int call_xms0(unsigned fn, unsigned arg)
{
int rc, err;
asm volatile("lcall *%[x]\n"
: "=a"(rc), "=b"(err)
: [x]"m"(xms), "a"(fn << 8), "d"(arg)
: "cc", "memory");
if (!rc)
printf("xms error %x\n", err & 0xff);
return rc;
}
static int call_xms_dxbx(unsigned fn, unsigned arg, unsigned *ret)
{
int rc;
unsigned dx, bx;
asm volatile("lcall *%[x]\n"
: "=a"(rc), "=d"(dx), "=b"(bx)
: [x]"m"(xms), "a"(fn << 8), "d"(arg)
: "cc", "memory");
*ret = (dx << 16) | bx;
return rc;
}
static int call_xms_dssi(unsigned fn, void *ptr)
{
int rc, err;
asm volatile("lcall *%[x]\n"
: "=a"(rc), "=b"(err)
: [x]"m"(xms), "a"(fn << 8), "S"(ptr)
: "cc", "memory");
if (!rc)
printf("xms error %x\n", err & 0xff);
return rc;
}
int main()
{
unsigned handle;
unsigned addr;
char *ptr;
char buf[PAGE_SIZE];
int err;
__dpmi_meminfo dm = {};
__dpmi_regs r = {};
static const char *str1 = "request";
static const char *str2 = "response";
const int offs1 = 35;
const int offs2 = 174;
/* check xms */
r.x.ax = 0x4300;
__dpmi_int(0x2f, &r);
if (r.h.al != 0x80) {
printf("FAILURE: XMS unsupported\n");
exit(1);
}
printf("XMS present\n");
/* get entry */
asm volatile(
"int $0x2f\n"
"mov %%es, %0\n"
: "=r"(xms.selector), "=b"(xms.offset32)
: "a"(0x4310));
printf("XMS at %x:%lx\n", xms.selector, xms.offset32);
/* alloc one page emb */
if (!call_xms(9, 4, &handle)) {
printf("FAILURE: EMB alloc failed\n");
exit(1);
}
printf("XMS alloc ok\n");
/* put test string there - length must be even */
e.Length = (strlen(str1) + 1 + 1) & ~1;
e.SourceHandle = 0;
e.SourceOffset = (uintptr_t)str1;
e.DestHandle = handle;
e.DestOffset = offs1;
if (!call_xms_dssi(0xb, &e)) {
printf("FAILURE: XMS move failed\n");
exit(1);
}
printf("XMS move ok\n");
/* map EMB */
if (!call_xms_dxbx(0xc, handle, &addr)) {
printf("FAILURE: XMS map failed\n");
exit(1);
}
printf("XMS map ok\n");
dm.address = addr;
dm.size = PAGE_SIZE;
err = __dpmi_physical_address_mapping(&dm);
if (err) {
printf("FAILURE: failed to get XMS page\n");
exit(1);
}
printf("DPMI map ok, addr=0x%08lx\n", dm.address);
/* enable 4G wrap-around */
if (!__djgpp_nearptr_enable()) {
printf("FAILURE: 4G wrap-around failed\n");
exit(1);
}
ptr = (char *)(dm.address + __djgpp_conventional_base);
printf("DPMI wrap-around ok, ptr=%p, base=%08x\n", ptr,
-__djgpp_conventional_base);
printf("Got this string: %s\n", ptr + offs1);
if (strcmp(str1, ptr + offs1) != 0)
printf("FAILURE: Test 1 FAILURE\n");
else
printf("Test 1 OK\n");
strcpy(ptr + offs2, str2);
/* disable wrap */
__djgpp_nearptr_disable();
/* unmap */
err = __dpmi_free_physical_address_mapping(&dm);
if (err) {
printf("FAILURE: failed to put XMS page\n");
exit(1);
}
if (!call_xms0(0xd, handle)) {
printf("FAILURE: XMS unmap failed\n");
exit(1);
}
printf("XMS unmap ok\n");
/* copy back our page */
e.Length = PAGE_SIZE;
e.SourceHandle = handle;
e.SourceOffset = offs2;
e.DestHandle = 0;
e.DestOffset = (uintptr_t)buf;
if (!call_xms_dssi(0xb, &e)) {
printf("XMS bad move2 failed, OK\n");
// exit(1);
}
e.Length -= offs2;
if (!call_xms_dssi(0xb, &e)) {
printf("FAILURE: XMS move2 failed\n");
exit(1);
}
printf("XMS move2 ok\n");
printf("Got back this string: %s\n", buf);
if (strcmp(str2, buf) != 0)
printf("FAILURE: Test 2 FAILURE\n");
else
printf("Test 2 OK\n");
return 0;
}
""")
results = self.runDosemu("testit.bat", config=CONFIG)
self.assertIn("Test 1 OK", results)
self.assertIn("Test 2 OK", results)
self.assertNotIn("FAILURE:", results)

View File

@@ -1,21 +1,19 @@
from pathlib import Path
from os import makedirs
from os.path import join
from common_framework import (VFAT_MNTPNT,
setup_vfat_mounted_image, teardown_vfat_mounted_image)
def mfs_truename(self, fstype, tocreate, tests):
def mfs_truename(self, fstype, tocreate, nametype, instring, expected):
ename = "mfstruen"
if fstype == "UFS":
testdir = Path("test-imagedir/dXXXXs/d")
testdir.mkdir(parents=True, exist_ok=True)
testdir = "test-imagedir/dXXXXs/d"
makedirs(testdir, exist_ok=True)
batchfile = """\
mkdir RootC
d:
cd Sub
c:\\%s
%s
rem end
""" % ename
@@ -25,15 +23,13 @@ $_floppy_a = ""
"""
elif fstype == "VFAT":
testdir = Path(VFAT_MNTPNT)
testdir = VFAT_MNTPNT
setup_vfat_mounted_image(self)
batchfile = """\
lredir X: /mnt/dosemu
lredir
mkdir RootC
x:
cd Sub
c:\\%s
rem end
""" % ename
@@ -49,97 +45,93 @@ $_lredir_paths = "/mnt/dosemu"
# Make test files and directory names
for i in tocreate:
p = testdir / i[1]
if i[0] == "FILE":
p.parents[0].mkdir(parents=True, exist_ok=True)
p.write_text("Some data")
with open(join(testdir, i[1]), "w") as f:
f.write("Some data")
elif i[0] == "DIR":
p.mkdir(parents=True, exist_ok=True)
makedirs(join(testdir, i[1]), exist_ok=True)
if nametype == "LFN0":
intnum = "0x7160"
qtype = "0"
elif nametype == "LFN1":
intnum = "0x7160"
qtype = "1"
elif nametype == "LFN2":
intnum = "0x7160"
qtype = "2"
elif nametype == "SFN":
intnum = "0x6000"
qtype = "0"
else:
self.fail("Incorrect argument")
# common
self.mkfile("testit.bat", batchfile, newline="\r\n")
def mkctests(xtests):
cnv = {
'LFN0': ('0x7160', '0'),
'LFN1': ('0x7160', '1'),
'LFN2': ('0x7160', '2'),
'SFN': ('0x6000', '0'),
}
results = "test_t test[] = {\n"
for t in xtests:
results += ' {%s, %s, "%s", "%s"},\n' % (*cnv[t[0]], t[1], t[2])
results += ' };\n'
results += ' int tlen = %d;' % len(xtests)
return results
# compile sources
self.mkcom_with_ia16(ename, r"""
self.mkcom_with_gas(ename, r"""
.text
.code16
#include <i86.h>
#include <stdio.h>
#include <stdint.h>
#include <string.h>
.globl _start16
_start16:
typedef struct {
uint16_t intr;
uint8_t tipo;
const char *input;
const char *expected;
} test_t;
push %%cs
pop %%ds
push %%cs
pop %%es
%s
char dst[1024];
movw $%s, %%ax
movw $%s, %%cx
movw $src, %%si
movw $dst, %%di
int $0x21
int main(void)
{
int ret = 0;
union REGS r = {};
struct SREGS rs;
int i;
movw $128, %%cx
movb $0, %%al
cld
repne scasb
movb $')', -1(%%di)
movb $'$', (%%di)
for (i = 0; i < tlen; i++) {
r.x.ax = test[i].intr;
if (r.x.ax == 0x7160)
r.x.cx = test[i].tipo;
rs.ds = FP_SEG(test[i].input);
r.x.si = FP_OFF(test[i].input);
rs.es = FP_SEG(dst);
r.x.di = FP_OFF(dst);
// need to set CF so we can detect if the function is implemented
r.x.cflag = 1;
int86x(0x21, &r, &r, &rs);
if (r.x.cflag) {
if (r.x.ax == 0x7100) {
snprintf(dst, sizeof(dst), "ERROR: not implemented, or perhaps ignored as not our drive\n");
} else if (r.x.ax == 0x2) {
snprintf(dst, sizeof(dst), "ERROR: invalid component");
} else if (r.x.ax == 0x3) {
snprintf(dst, sizeof(dst), "ERROR: malformed path or invalid drive letter");
} else {
snprintf(dst, sizeof(dst), "ERROR: unknown error code 0x%%04x", r.x.ax);
}
}
jnc prsucc
if (strcmp(dst, test[i].expected) != 0) {
printf("FAIL: 0x%%04x/%%d, (sent '%%s', expected '%%s', got '%%s')\n",
test[i].intr, test[i].tipo, test[i].input, test[i].expected, dst);
ret += 1;
} else {
if (test[i].intr == 0x7160) {
printf("OKAY: 0x%%04x/%%d, (sent '%%s', got '%%s')\n",
test[i].intr, test[i].tipo, test[i].input, dst);
} else {
printf("OKAY: 0x%%04x , (sent '%%s', got '%%s')\n",
test[i].intr, test[i].input, dst);
}
}
}
prfail:
movw $failmsg, %%dx
movb $0x9, %%ah
int $0x21
if (ret == 0)
printf("PASS:\n");
return ret;
}
""" % mkctests(tests))
jmp exit
prsucc:
movw $succmsg, %%dx
movb $0x9, %%ah
int $0x21
prresult:
movb $0x9, %%ah
movw $pdst, %%dx
int $0x21
exit:
movb $0x4c, %%ah
int $0x21
src:
.asciz "%s"
succmsg:
.ascii "Directory Operation Success\r\n$"
failmsg:
.ascii "Directory Operation Failed\r\n$"
pdst:
.byte '('
dst:
.fill 128, 1, '$'
""" % (intnum, qtype, instring.replace("\\", "\\\\")))
results = self.runDosemu("testit.bat", config=config)
@@ -147,4 +139,8 @@ int main(void)
teardown_vfat_mounted_image(self)
self.assertRegex(results, r"X: = .*LINUX\\FS/mnt/dosemu")
self.assertNotIn("FAIL", results)
if expected is None:
self.assertIn("Directory Operation Failed", results)
else:
self.assertIn("Directory Operation Success", results)
self.assertIn("(" + expected + ")", results)

View File

@@ -1,88 +0,0 @@
from http.server import BaseHTTPRequestHandler, HTTPServer
import threading
from common_framework import setup_tap_interface, teardown_tap_interface
# Note: this is the address assigned to libvirt's virbr0 bridge interface
HOST = '192.168.122.1'
PORT = 8080
CONTENT = b"""\
This is very short string. Ideally we'd use the new random byte generator
in python 3.9, but not all test platforms have that yet(mine included)"""
class MyServer(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-type", "application/octet-stream")
self.end_headers()
self.wfile.write(CONTENT)
raise KeyboardInterrupt # Close afterwards
def log_message(self, format, *args):
pass # Quieten stderr
def little_webserver():
with HTTPServer((HOST, PORT), MyServer) as ws:
try:
ws.serve_forever()
except KeyboardInterrupt:
pass
def network_pktdriver_mtcp(self, driver):
setup_tap_interface(self)
self.addCleanup(teardown_tap_interface, self)
thread = threading.Thread(target=little_webserver, daemon=True)
thread.start()
self.unTarOrSkip("TEST_CRYNWR.tar", [
("ne2000.com", "297cf2bc04aded016bb8051a9d2b061940c39569"),
])
self.unTarOrSkip("TEST_MTCP.tar", [
("dhcp.exe", "3658786197def91dce139f0d2aa1524ba409e426"),
("htget.exe", "26e72660d62a274577e874ba68bd6af03962fcce"),
("ping.exe", "6f8814e9ef4366b0a7597f005d1aad587eb6fc93"),
("pkttool.exe", "66a26d7fc18c0102ba6672c37fb6b04a027dc6ee"),
])
# Note: Only load the DOS NE2000 driver if you are going to use it
# as it interferes with the builtin packet driver's receipt
# of packets.
if driver == 'ne2000':
pktintr = '0x61'
mtcpcfg = 'c:\\ne2000 %s 10 0x310' % pktintr
else:
pktintr = '0x60'
mtcpcfg = ''
self.mkfile("mtcp.cfg", """\
packetint %s
hostname dosemu
dhcp_lease_request_secs 3600
dhcp_lease_threshold 360
""" % pktintr, newline="\r\n")
self.mkfile("testit.bat", """\
%s
set MTCPCFG=c:\\mtcp.cfg
dhcp
htget -o test.fil http://%s:%d/test.fil
rem end
""" % (mtcpcfg, HOST, PORT), newline="\r\n")
results = self.runDosemu("testit.bat", config="""\
$_hdimage = "dXXXXs/c:hdtype1 +1"
$_floppy_a = ""
$_pktdriver = (on)
$_vnet = "tap"
$_tapdev = "tap0"
""", timeout=30)
testfil = self.workdir / 'test.fil'
self.assertEqual(CONTENT, testfil.read_bytes())

View File

@@ -1,138 +0,0 @@
def pit_mode_2(self):
self.mkfile("testit.bat", """\
pitmode2
rem end
""", newline="\r\n")
# compile sources
self.mkcom_with_ia16("pitmode2", r"""
/*
Sample program #15
Demonstrates absolute timestamping in mode two
Part of the PC Timing FAQ / Application notes
By K. Heidenstrom (kheidens@actrix.gen.nz)
Rewritten to be non-interactive and compile with ia16-elf-gcc
*/
#define _BORLANDC_SOURCE
#include <conio.h>
#include <dos.h>
#include <stdio.h>
typedef struct {
unsigned int part;
unsigned long ticks;
} __attribute__((packed)) timestamp;
// #define BIOS_TICK_COUNT_P ((volatile unsigned long far *)0x0040006CL)
volatile unsigned long __far *BIOS_TICK_COUNT_P = MK_FP(0x0040, 0x006C);
void set_mode2(void)
{
unsigned int tick_loword;
tick_loword = *BIOS_TICK_COUNT_P;
while ((unsigned int)*BIOS_TICK_COUNT_P == tick_loword)
/* do nothing */;
#if 0
asm pushf;
asm cli;
outportb(0x43, 0x34); /* Channel 0, mode 2 */
outportb(0x40, 0x00); /* Loword of divisor */
outportb(0x40, 0x00); /* Hiword of divisor */
asm popf;
#endif
asm volatile("pushf\n"
"push %%ax\n"
"cli\n"
"mov $0x34, %%al\n"
"outb %%al, $0x43\n" /* Channel 0, mode 2 */
"mov $0x00, %%al\n"
"outb %%al, $0x40\n" /* Loword of divisor */
"outb %%al, $0x40\n" /* Hiword of divisor */
"pop %%ax\n"
"popf\n"
:
:
:
);
return;
}
void get_timestamp(timestamp *tsp)
{
unsigned long tickcount1, tickcount2;
unsigned int ctcvalue;
unsigned char ctclow, ctchigh;
again:
tickcount1 = *BIOS_TICK_COUNT_P;
outportb(0x43, 0); /* Latch value */
ctclow = inportb(0x40);
ctchigh = inportb(0x40); /* Read count in progress */
ctcvalue = -((ctchigh << 8) + ctclow);
tickcount2 = *BIOS_TICK_COUNT_P;
if (tickcount2 != tickcount1)
goto again;
tsp->ticks = tickcount1;
tsp->part = ctcvalue;
return;
}
int main(void)
{
timestamp ts, ts1, ts2;
uint64_t start;
printf("Sample program #15 - Demonstrates absolute timestamping\n");
printf("Part of the PC Timing FAQ / Application notes\n");
printf("By K. Heidenstrom (kheidens@actrix.gen.nz)\n\n");
set_mode2();
// Info
get_timestamp(&ts); /* Get timestamp */
printf("Absolute timestamp: 0x%04X%04X%04X units of 0.8381 us\n", (unsigned int)(ts.ticks >> 16),
(unsigned int)(ts.ticks & 0xFFFF), ts.part);
// Continuous test for 2 minutes
printf("\nContinuous timestamp test - start\n\n");
for (start = (ts.ticks << 16) + ts.part; /* */; /* */) {
ts2.ticks = ts1.ticks;
ts2.part = ts1.part;
ts1.ticks = ts.ticks;
ts1.part = ts.part;
get_timestamp(&ts);
// printf("0x%04X%04X%04X\r", (unsigned int)(ts.ticks >> 16), (unsigned int)(ts.ticks & 0xFFFF), ts.part);
if ((ts.ticks < ts1.ticks) || ((ts.ticks == ts1.ticks) && (ts.part < ts1.part))) { /* Went backwards? */
printf("Timestamp went backwards: 0x%04X%04X%04X, 0x%04X%04X%04X, then 0x%04X%04X%04X\n",
(unsigned int)(ts2.ticks >> 16), (unsigned int)(ts2.ticks & 0xFFFF), ts2.part,
(unsigned int)(ts1.ticks >> 16), (unsigned int)(ts1.ticks & 0xFFFF), ts1.part,
(unsigned int)(ts.ticks >> 16), (unsigned int)(ts.ticks & 0xFFFF), ts.part);
}
if (((uint64_t)((ts.ticks << 16) + ts.part) - start) > 143181004) // 120 secs: 120/(0.8381/1000000)
break;
}
printf("\nContinuous timestamp test - complete\n\n");
return 0;
}
""")
starttime = self.utcnow()
results = self.runDosemu("testit.bat", config="""\
$_hdimage = "dXXXXs/c:hdtype1 +1"
$_floppy_a = ""
""", timeout=150)
endtime = self.utcnow()
self.assertIn("Continuous timestamp test - complete", results)
self.assertNotIn("Timestamp went backwards", results)
self.assertLess((endtime - starttime).seconds, 125)

File diff suppressed because it is too large Load Diff