diff --git a/kern.h b/kern.h index e218f1b..818a4d1 100644 --- a/kern.h +++ b/kern.h @@ -19,6 +19,8 @@ extern int KERN_CALL C32_CallVersion_Nios_Probe(void *outbuf); extern int KERN_CALL Net_Call_VLM_Raw(UI ax, UI bx, UI cx, UI dx, void *req, void *repl, UI p1, UI p2, UI p3); +extern int KERN_CALL Net_Call_NWCVLMREQ(UI flags, void *regblk, + UI p1, UI p2, UI p3); extern int KERN_CALL Net_Call_C(UI func, void *req, void *repl); extern int KERN_CALL Net_Call_CX(UI func, UI bx, UI cx, UI dx, void *req, void *repl); diff --git a/kern_wasm.asm b/kern_wasm.asm index fbb8c8d..9731b76 100644 --- a/kern_wasm.asm +++ b/kern_wasm.asm @@ -24,6 +24,7 @@ public _C32_LoadNios_Probe public _C32_GetFunc_Probe public _C32_CallVersion_Nios_Probe public _Net_Call_VLM_Raw +public _Net_Call_NWCVLMREQ _IPXinit proc far push bp @@ -592,4 +593,115 @@ c32ver_name db 'CLIENT32GetVersion',0 _C32_CallVersion_Nios_Probe endp +; int Net_Call_NWCVLMREQ(UI flags, void *regblk, UI p1, UI p2, UI p3) +; +; 16-bit wrapper that reproduces the DeveloperNet NWCVLMREQ register-block +; calling convention, but without using Novell globals. +; +; regblk layout, same as dvlmreq.o: +; +00 SI +; +02 DS +; +04 DI +; +06 ES +; +08 AX +; +0A BX +; +0C CX +; +0E DX +; +; It calls the VLM entry returned by INT 2F AX=7A20. +; Stack args are pushed as p3,p2,p1, exactly like NWCVLMREQ. +_Net_Call_NWCVLMREQ proc far + push bp + mov bp, sp + sub sp, 4 + + push ds + push si + push di + push es + + mov ax, 7A20h + xor bx, bx + int 2Fh + or ax, ax + jz nwcvlm_found + + mov ax, 88FFh + jmp short nwcvlm_done + +nwcvlm_found: + ; save VLM entry ES:BX in [bp-4] + mov [bp-4], bx + mov ax, es + mov [bp-2], ax + + les bx, dword ptr [bp+8] ; regblk + + ; Match NWCVLMREQ defaulting: + ; if !(flags & 2), set regblk.ES to current ES. + ; We normally pass flags=2, so this is skipped. + test word ptr [bp+6], 2 + jne nwcvlm_skip_es + mov ax, es + mov word ptr es:[bx+6], ax +nwcvlm_skip_es: + + ; if !(flags & 1), set regblk.DS to current DS. + test word ptr [bp+6], 1 + jne nwcvlm_skip_ds + mov ax, ds + mov word ptr es:[bx+2], ax +nwcvlm_skip_ds: + + ; Load target registers from regblk. + mov ax, word ptr es:[bx+0Ah] + push ax ; target BX + mov ax, word ptr es:[bx+6] + push ax ; target ES + + mov ax, word ptr es:[bx+8] + mov cx, word ptr es:[bx+0Ch] + mov dx, word ptr es:[bx+0Eh] + mov si, word ptr es:[bx+0] + mov di, word ptr es:[bx+4] + mov ds, word ptr es:[bx+2] + + pop es + pop bx + + push word ptr [bp+18] ; p3 + push word ptr [bp+16] ; p2 + push word ptr [bp+14] ; p1 + call dword ptr [bp-4] + + ; Store registers back into regblk. + push bx + push es + + les bx, dword ptr [bp+8] + mov word ptr es:[bx+8], ax + pop ax + mov word ptr es:[bx+6], ax + pop ax + mov word ptr es:[bx+0Ah], ax + mov word ptr es:[bx+0Ch], cx + mov word ptr es:[bx+0Eh], dx + mov word ptr es:[bx+0], si + mov word ptr es:[bx+4], di + mov word ptr es:[bx+2], ds + + mov ax, word ptr es:[bx+8] + +nwcvlm_done: + pop es + pop di + pop si + pop ds + + mov sp, bp + pop bp + ret +_Net_Call_NWCVLMREQ endp + + end diff --git a/nwtests.c b/nwtests.c index c5dfb8b..1b08285 100644 --- a/nwtests.c +++ b/nwtests.c @@ -1259,6 +1259,81 @@ static int tests_c32callver2(void) } +static void tests_set_reg_word(uint8 *r, int off, UI val) +{ + tests_put_word_lh(r + off, (uint16)val); +} + +static UI tests_get_reg_word(uint8 *r, int off) +{ + return (UI)(r[off] | ((UI)r[off + 1] << 8)); +} + +static void tests_dump_vlm_regs(char *title, uint8 *r) +{ + fprintf(stdout, "%s SI=%04X DS=%04X DI=%04X ES=%04X AX=%04X BX=%04X CX=%04X DX=%04X\n", + title, + tests_get_reg_word(r, 0), + tests_get_reg_word(r, 2), + tests_get_reg_word(r, 4), + tests_get_reg_word(r, 6), + tests_get_reg_word(r, 8), + tests_get_reg_word(r, 10), + tests_get_reg_word(r, 12), + tests_get_reg_word(r, 14)); +} + +static int tests_c32mapconn(void) +{ + int drive; + uint8 connid = 0; + uint8 dhandle = 0; + uint8 flags = 0; + uint8 regs[16]; + uint8 reply[128]; + int rc; + + drive = tests_get_current_drive(); + if (get_drive_info((uint8)drive, &connid, &dhandle, &flags)) { + fprintf(stdout, "get_drive_info failed\n"); + return(1); + } + + memset(regs, 0, sizeof(regs)); + memset(reply, 0, sizeof(reply)); + + /* + * First half of DeveloperNet __C32MapConn16To32: + * + * reg.CX = conn16 + * reg.ES:DI = reply buffer + * NWCVLMREQ(flags=2, regblk, p1=0Dh, p2=10h, p3=0) + * + * The reply buffer should contain the connection/server reference string + * that w95mconn.o later passes to NWCSCANCONNINFO. + */ + tests_set_reg_word(regs, 4, FP_OFF(reply)); /* DI */ + tests_set_reg_word(regs, 6, FP_SEG(reply)); /* ES */ + tests_set_reg_word(regs, 12, connid); /* CX */ + + fprintf(stdout, "TEST C32MAPCONN step1, __C32MapConn16To32 VLM probe\n"); + fprintf(stdout, "drive=%c: connid=%u dhandle=%u flags=%02X\n", + 'A' + drive, connid, dhandle, flags); + tests_dump_vlm_regs("REG in :", regs); + fprintf(stdout, "Call NWCVLMREQ flags=2 p1=000D p2=0010 p3=0000\n"); + + rc = Net_Call_NWCVLMREQ(2, regs, 0x000D, 0x0010, 0); + + fprintf(stdout, "NWCVLMREQ rc=%04X\n", rc); + tests_dump_vlm_regs("REG out:", regs); + tests_dump_bytes("REPLY:", reply, 64); + fprintf(stdout, "REPLY text: %s\n", reply); + + fprintf(stdout, "\nIf REPLY contains a server/conn string, next step is NWCSCANCONNINFO.\n"); + return(0); +} + + int func_tests(int argc, char *argv[], int mode) { if (argc >= 2) { @@ -1277,6 +1352,9 @@ int func_tests(int argc, char *argv[], int mode) if (tests_same_arg(argv[1], "C32CALLVER2")) return tests_c32callver2(); + if (tests_same_arg(argv[1], "C32MAPCONN")) + return tests_c32mapconn(); + if (tests_same_arg(argv[1], "NWREQ87")) return tests_nwreq87(argc, argv);