This commit is contained in:
Mario Fetka
2026-05-23 15:09:50 +02:00
parent ed5da6c063
commit 99c3eed1bf
3 changed files with 177 additions and 1 deletions

45
kern.c
View File

@@ -179,6 +179,51 @@ int KERN_C_CALL Net_Call_F2_C(unsigned int function,
return (int)(ret_ax & 0x00ff);
}
/*
* Fully generic INT 21h register test wrapper.
* Used for reproducing the NWCREQUEST/NWCSHELLREQ register calls seen in
* DeveloperNet 1997 clndos16.lib.
*/
int KERN_C_CALL Net_Call_F2X_C(unsigned int ax,
unsigned int bx,
unsigned int cx,
unsigned int dx,
void *req,
void *repl)
{
union REGS inregs;
union REGS outregs;
struct SREGS segregs;
unsigned int ret_ax;
memset(&inregs, 0, sizeof(inregs));
memset(&outregs, 0, sizeof(outregs));
memset(&segregs, 0, sizeof(segregs));
net_call_c_clear();
inregs.x.ax = ax;
inregs.x.bx = bx;
inregs.x.cx = cx;
inregs.x.dx = dx;
inregs.x.si = FP_OFF(req);
inregs.x.di = FP_OFF(repl);
segregs.ds = FP_SEG(req);
segregs.es = FP_SEG(repl);
net_call_c_save_in(&inregs, &segregs, req, repl);
int86x(0x21, &inregs, &outregs, &segregs);
ret_ax = outregs.x.ax & 0x00ff;
if (ret_ax)
ret_ax |= 0x8900;
net_call_c_save_out(&outregs, ret_ax);
return (int)(ret_ax & 0x00ff);
}
void KERN_C_CALL Net_Call_C_Dump(void)
{
fprintf(stdout, "NETCALLC in : AX=%04X BX=%04X CX=%04X DX=%04X DS:SI=%04X:%04X ES:DI=%04X:%04X\n",

2
kern.h
View File

@@ -18,6 +18,8 @@ extern int KERN_CALL Net_Call_CX(UI func, UI bx, UI cx, UI dx,
void *req, void *repl);
extern int KERN_CALL Net_Call_F2_C(UI function, UI req_len, UI repl_len,
void *req, void *repl);
extern int KERN_CALL Net_Call_F2X_C(UI ax, UI bx, UI cx, UI dx,
void *req, void *repl);
extern void KERN_CALL Net_Call_C_Dump(void);
extern UI KERN_CALL Net_Call_C_GetDebug(UI idx);

131
nwtests.c
View File

@@ -21,7 +21,7 @@ static int tests_same_arg(char *a, char *b)
static void tests_usage(void)
{
fprintf(stdout, "Usage: TESTS [OLD|NETCALL|E300|NCPF2 [file] [REPLY]]\n");
fprintf(stdout, "Usage: TESTS [OLD|NETCALL|E300|NCPF2 [file]|NWREQ87 [file]]\n");
}
static int tests_netcall(void)
@@ -300,6 +300,132 @@ static int tests_ncpf2(int argc, char *argv[])
}
static void tests_build_nwreq87_path(uint8 *buf, uint8 dhandle,
char *name, UI *out_len)
{
uint8 *p;
int nlen;
memset(buf, 0, 300);
p = buf;
nlen = strlen(name);
if (nlen > 255) nlen = 255;
/*
* Same compact handle/path payload we used before:
* handle, dirbase, dirstyle, component-count, len, name
* The new part in this test is not the path itself; it is that we now
* reproduce NWCREQUEST's fragmented request and full reply size.
*/
*p++ = dhandle;
tests_put_dword_lh(p, 0L); p += 4;
*p++ = 0; /* dirstyle = short directory handle */
*p++ = 1; /* one path component */
*p++ = (uint8)nlen;
memcpy(p, name, nlen);
p += nlen;
*out_len = (UI)(p - buf);
}
static UI tests_build_nwreq87s6_flat(uint8 *req,
uint8 *path,
UI path_len)
{
uint8 *p;
memset(req, 0, 400);
p = req;
/*
* DeveloperNet ncpdos16 87s6.c builds two request fragments:
* frag 1 length 9:
* subfn=6, srcNS, dstNS, searchAttrs, returnInfoMask
* frag 2:
* packed handle/path structure
*
* NWCREQUEST for NETX/Shell concatenates those request fragments before
* calling NWCSHELLREQ.
*/
*p++ = 6; /* NCP87 subfunction 6 */
*p++ = 0; /* source namespace DOS */
*p++ = 0; /* target namespace DOS */
tests_put_word_lh(p, 0x0006); p += 2; /* SA_ALL */
tests_put_dword_lh(p, 0x00000004UL); p += 4;/* RIM_ATTRIBUTES */
memcpy(p, path, path_len);
p += path_len;
return (UI)(p - req);
}
static int tests_nwreq87(int argc, char *argv[])
{
char *name = "LOGIN.EXE";
uint8 connid = 0;
uint8 dhandle = 0;
uint8 path[300];
uint8 req[400];
uint8 repl[0x180];
uint8 dummy[8];
UI path_len;
UI req_len;
int rc;
uint32 a0;
uint32 a4;
uint32 a4d;
if (argc > 2)
name = argv[2];
if (tests_current_conn_dhandle(&connid, &dhandle))
return(1);
tests_build_nwreq87_path(path, dhandle, name, &path_len);
req_len = tests_build_nwreq87s6_flat(req, path, path_len);
memset(repl, 0, sizeof(repl));
memset(dummy, 0, sizeof(dummy));
fprintf(stdout, "TEST NWREQ87 shell-style NCP87/S6 for %s\n", name);
fprintf(stdout, "connid=%u dhandle=%u path.len=%u req.len=%u repl.len=%u\n",
connid, dhandle, path_len, req_len, (UI)0x014d);
tests_dump_bytes("NWREQ87 path:", path, path_len > 48 ? 48 : path_len);
tests_dump_bytes("NWREQ87 req :", req, req_len > 64 ? 64 : req_len);
/*
* Reproduce the NETX/Shell path in clndos16 dreq.c:
* first AH=F0/DX=conn via NWCSHELLREQ
* then AH=F2/AL=function with DS:SI=request, CX=requestLen,
* ES:DI=reply, DX=sum(replyFragLengths).
*
* For 87s6.c reply fragments are 0x4d + 0x100 = 0x014d.
*/
fprintf(stdout, "NWREQ87 init F000 DX=conn\n");
rc = Net_Call_F2X_C(0xF000, 0, 0, (UI)connid, dummy, repl);
fprintf(stdout, "NWREQ87 init rc=%04X\n", rc);
Net_Call_C_Dump();
fprintf(stdout, "NWREQ87 call F257 CX=req.len DX=014D\n");
rc = Net_Call_F2X_C(0xF257, 0, req_len, 0x014d, req, repl);
fprintf(stdout, "NWREQ87 rc=%04X\n", rc);
Net_Call_C_Dump();
tests_dump_bytes("NWREQ87 repl[0..63]:", repl, 64);
tests_dump_bytes("NWREQ87 repl[4d..8c]:", repl + 0x4d, 64);
a0 = tests_get_dword_lh(repl);
a4 = tests_get_dword_lh(repl + 4);
a4d = tests_get_dword_lh(repl + 0x4d);
fprintf(stdout, "NWREQ87 dword[0]=%08lX dword[4]=%08lX dword[4d]=%08lX\n",
a0, a4, a4d);
return(0);
}
int func_tests(int argc, char *argv[], int mode)
{
if (argc >= 2) {
@@ -309,6 +435,9 @@ int func_tests(int argc, char *argv[], int mode)
if (tests_same_arg(argv[1], "E300") || tests_same_arg(argv[1], "NETCALLE300"))
return tests_netcall_e300();
if (tests_same_arg(argv[1], "NWREQ87"))
return tests_nwreq87(argc, argv);
if (tests_same_arg(argv[1], "NCPF2"))
return tests_ncpf2(argc, argv);