/* * kern.c - C-side experimental NetWare/DOS request wrappers * * kern_wasm.asm remains the production/reference implementation. * These C functions are test wrappers so we can inspect register setup and * slowly port proven pieces from ASM to C. */ #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; static void net_call_c_clear(void) { memset(&Net_Call_C_Last, 0, sizeof(Net_Call_C_Last)); } static void net_call_c_save_in(union REGS *r, struct SREGS *s, void *req, void *repl) { Net_Call_C_Last.in_ax = r->x.ax; Net_Call_C_Last.in_bx = r->x.bx; Net_Call_C_Last.in_cx = r->x.cx; Net_Call_C_Last.in_dx = r->x.dx; Net_Call_C_Last.in_si = r->x.si; Net_Call_C_Last.in_di = r->x.di; Net_Call_C_Last.in_ds = s->ds; Net_Call_C_Last.in_es = s->es; Net_Call_C_Last.req_ptr = req; Net_Call_C_Last.repl_ptr = repl; } static void net_call_c_save_out(union REGS *r, unsigned int returned_ax) { Net_Call_C_Last.out_ax = returned_ax; Net_Call_C_Last.out_bx = r->x.bx; Net_Call_C_Last.out_cx = r->x.cx; Net_Call_C_Last.out_dx = r->x.dx; Net_Call_C_Last.out_si = r->x.si; Net_Call_C_Last.out_di = r->x.di; Net_Call_C_Last.out_flags = r->x.cflag; Net_Call_C_Last.rc = returned_ax & 0x00ff; } /* * C equivalent of kern_wasm.asm Net_Call: * AX = func * DS:SI = request * ES:DI = reply * int 21h * return AL only, because kern_wasm.asm clears AH before return. */ int KERN_C_CALL Net_Call_C(unsigned int ax, void *req, void *repl) { return Net_Call_CX(ax, 0, 0, 0, req, repl); } 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; 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; /* match ASM Net_Call return */ net_call_c_save_out(&outregs, ret_ax); return (int)ret_ax; } /* * Experimental Novell Client/VLM AH=F2 wrapper derived from official FLAG.EXE * disassembly: * AH = F2h * AL = NCP function, e.g. 57h for NCP 87 * CX = request length * DX = reply buffer length * DS:SI = request buffer * ES:DI = reply buffer */ int KERN_C_CALL Net_Call_F2_C(unsigned int function, unsigned int req_len, unsigned int repl_len, 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.h.ah = 0xF2; inregs.h.al = (unsigned char)(function & 0xff); inregs.x.cx = req_len; inregs.x.dx = repl_len; 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); /* * Novell wrapper behavior: * xor ah,ah * or al,al * if al != 0: ah=89h * Return AL only for C caller, but keep 89xx in debug out_ax. */ 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); } /* * 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", 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); } unsigned int KERN_C_CALL Net_Call_C_GetDebug(unsigned int 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; }