This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
4493
test/cpu/reffile.log
4493
test/cpu/reffile.log
File diff suppressed because it is too large
Load Diff
@@ -77,7 +77,3 @@ myfunc2:
|
||||
|
||||
|
||||
code16_end:
|
||||
|
||||
#ifdef __ELF__
|
||||
.section .note.GNU-stack,"",%progbits
|
||||
#endif
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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 $@ $<
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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))
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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"
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
@@ -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)
|
||||
|
||||
@@ -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())
|
||||
@@ -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)
|
||||
3021
test/test_dos.py
3021
test/test_dos.py
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user