227 lines
5.9 KiB
C
227 lines
5.9 KiB
C
/*
|
|
* 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 <stdio.h>
|
|
#include <string.h>
|
|
#include <dos.h>
|
|
|
|
#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);
|
|
}
|
|
|
|
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;
|
|
}
|