/* * kern.c - C-side experimental NetWare/DOS request wrapper * * This does NOT replace kern.asm. It adds separate functions so we can test * register/segment handling and inspect the last call from DOS DEBUG or from * a small debug command later. * * Existing assembler function stays: * int Net_Call(unsigned int func, void *req, void *repl); * * New test functions: * int Net_Call_C(unsigned int ax, void *req, void *repl); * int Net_Call_CX(unsigned int ax, unsigned int bx, * unsigned int cx, unsigned int dx, * void *req, void *repl); * void Net_Call_C_Dump(void); */ #include #include #include #include "net.h" #if defined(__WATCOMC__) #define KERN_C_CALL _Cdecl #else #define KERN_C_CALL #endif typedef struct { unsigned int in_ax; unsigned int in_bx; unsigned int in_cx; unsigned int in_dx; unsigned int in_si; unsigned int in_di; unsigned int in_ds; unsigned int in_es; unsigned int out_ax; unsigned int out_bx; unsigned int out_cx; unsigned int out_dx; unsigned int out_si; unsigned int out_di; unsigned int out_flags; void far *req_ptr; void far *repl_ptr; int rc; } NET_CALL_C_DEBUG; NET_CALL_C_DEBUG Net_Call_C_Last; /* * Same call shape as kern.asm Net_Call, but implemented in C. * * This is meant for OLD known-working calls first: * Net_Call_C(0xE200, ...) * Net_Call_C(0xE300, ...) * * Do not use it blindly for NCP87 yet; the previous F257 test hung through * the old wrapper, so we will first test old calls and register layout. */ int KERN_C_CALL Net_Call_C(unsigned int ax, void *req, void *repl) { return Net_Call_CX(ax, 0, 0, 0, req, repl); } /* * Extended variant with BX/CX/DX settable. This lets us experiment without * changing kern.asm every time. */ int KERN_C_CALL Net_Call_CX(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; memset(&inregs, 0, sizeof(inregs)); memset(&outregs, 0, sizeof(outregs)); memset(&segregs, 0, sizeof(segregs)); memset(&Net_Call_C_Last, 0, sizeof(Net_Call_C_Last)); 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_Last.in_ax = inregs.x.ax; Net_Call_C_Last.in_bx = inregs.x.bx; Net_Call_C_Last.in_cx = inregs.x.cx; Net_Call_C_Last.in_dx = inregs.x.dx; Net_Call_C_Last.in_si = inregs.x.si; Net_Call_C_Last.in_di = inregs.x.di; Net_Call_C_Last.in_ds = segregs.ds; Net_Call_C_Last.in_es = segregs.es; Net_Call_C_Last.req_ptr = req; Net_Call_C_Last.repl_ptr = repl; int86x(0x21, &inregs, &outregs, &segregs); Net_Call_C_Last.out_ax = outregs.x.ax; Net_Call_C_Last.out_bx = outregs.x.bx; Net_Call_C_Last.out_cx = outregs.x.cx; Net_Call_C_Last.out_dx = outregs.x.dx; Net_Call_C_Last.out_si = outregs.x.si; Net_Call_C_Last.out_di = outregs.x.di; Net_Call_C_Last.out_flags = outregs.x.cflag; /* kern_wasm.asm clears AH before returning, so return AL only. */ Net_Call_C_Last.rc = outregs.x.ax & 0x00ff; return Net_Call_C_Last.rc; } /* * Experimental Client32/VLM-style AH=F2 raw request wrapper. * * This mirrors the official Novell FLAG.EXE wrapper shape seen in disassembly: * DX = connection / connection reference * ES:DI = reply buffer * CX = caller supplied size/count * DS:SI = request buffer * AH = F2h * AL = NCP function, e.g. 57h for NCP 87 * int 21h * * Return convention mirrors Novell wrapper and old kern.asm Net_Call: * if AL != 0, AH is set to 89h in Net_Call_F2_C_Last.out_ax * return AL only */ int KERN_C_CALL Net_Call_F2_C(UI conn, UI function, UI cx, void *req, void *repl) { union REGS inregs; union REGS outregs; struct SREGS segregs; UI ret_ax; memset(&inregs, 0, sizeof(inregs)); memset(&outregs, 0, sizeof(outregs)); memset(&segregs, 0, sizeof(segregs)); memset(&Net_Call_C_Last, 0, sizeof(Net_Call_C_Last)); inregs.h.ah = 0xF2; inregs.h.al = (uint8)(function & 0xff); inregs.x.dx = conn; inregs.x.cx = cx; 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_Last.in_ax = inregs.x.ax; Net_Call_C_Last.in_bx = inregs.x.bx; Net_Call_C_Last.in_cx = inregs.x.cx; Net_Call_C_Last.in_dx = inregs.x.dx; Net_Call_C_Last.in_si = inregs.x.si; Net_Call_C_Last.in_di = inregs.x.di; Net_Call_C_Last.in_ds = segregs.ds; Net_Call_C_Last.in_es = segregs.es; Net_Call_C_Last.req_ptr = req; Net_Call_C_Last.repl_ptr = repl; int86x(0x21, &inregs, &outregs, &segregs); ret_ax = outregs.x.ax; ret_ax &= 0x00ff; if (ret_ax) ret_ax |= 0x8900; Net_Call_C_Last.out_ax = ret_ax; Net_Call_C_Last.out_bx = outregs.x.bx; Net_Call_C_Last.out_cx = outregs.x.cx; Net_Call_C_Last.out_dx = outregs.x.dx; Net_Call_C_Last.out_si = outregs.x.si; Net_Call_C_Last.out_di = outregs.x.di; Net_Call_C_Last.out_flags = outregs.x.cflag; Net_Call_C_Last.rc = ret_ax & 0x00ff; return Net_Call_C_Last.rc; } /* * Text dump for quick testing. Later we can expose this through DEBUG.EXE * as "debug netcall" or similar. */ 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", Net_Call_C_Last.in_ax, Net_Call_C_Last.in_bx, Net_Call_C_Last.in_cx, Net_Call_C_Last.in_dx, Net_Call_C_Last.in_ds, Net_Call_C_Last.in_si, Net_Call_C_Last.in_es, Net_Call_C_Last.in_di); fprintf(stdout, "NETCALLC out: AX=%04X BX=%04X CX=%04X DX=%04X SI=%04X DI=%04X CF=%04X RC=%d\n", Net_Call_C_Last.out_ax, Net_Call_C_Last.out_bx, Net_Call_C_Last.out_cx, Net_Call_C_Last.out_dx, Net_Call_C_Last.out_si, Net_Call_C_Last.out_di, Net_Call_C_Last.out_flags, Net_Call_C_Last.rc); } /* * Optional helper for DEBUG-style commands that do not want formatted output. * idx: * 0 in_ax 1 in_bx 2 in_cx 3 in_dx * 4 in_ds 5 in_si 6 in_es 7 in_di * 8 out_ax 9 out_bx 10 out_cx 11 out_dx * 12 out_si 13 out_di 14 out_flags 15 rc */ UI KERN_C_CALL Net_Call_C_GetDebug(UI idx) { switch (idx) { case 0: return Net_Call_C_Last.in_ax; case 1: return Net_Call_C_Last.in_bx; case 2: return Net_Call_C_Last.in_cx; case 3: return Net_Call_C_Last.in_dx; case 4: return Net_Call_C_Last.in_ds; case 5: return Net_Call_C_Last.in_si; case 6: return Net_Call_C_Last.in_es; case 7: return Net_Call_C_Last.in_di; case 8: return Net_Call_C_Last.out_ax; case 9: return Net_Call_C_Last.out_bx; case 10: return Net_Call_C_Last.out_cx; case 11: return Net_Call_C_Last.out_dx; case 12: return Net_Call_C_Last.out_si; case 13: return Net_Call_C_Last.out_di; case 14: return Net_Call_C_Last.out_flags; case 15: return (unsigned int)Net_Call_C_Last.rc; } return 0xffff; }