; kern_wasm.asm ; ; Open Watcom WASM/MASM-syntax port of the old TASM IDEAL kern.asm. ; Intended for 16-bit DOS large memory model builds on Linux with Open Watcom v2. ; ; Keep kern.asm as the historical TASM source and use this file for the ; reproducible Open Watcom build. .286 .model large .data enterIPX dd 0 .code public _IPXinit public _IPXopen_socket public _IPXclose_socket public _IPXlisten public _xmemmove public _Net_Call public _C32_LoadNios_Probe public _C32_GetFunc_Probe public _C32_CallVersion_Nios_Probe public _C32_MapLock_Probe public _Net_Call_VLM_Raw _IPXinit proc far push bp mov bp, sp push ds push si push di mov ax, 7A00h int 2Fh cmp al, 0FFh jne ipxinit_done mov cx, @data mov ds, cx mov word ptr enterIPX, di mov ax, es mov word ptr enterIPX+2, ax mov al, 1 ipxinit_done: mov ah, 0 pop di pop si pop ds pop bp ret _IPXinit endp _xmemmove proc far push bp mov bp, sp ; far procedure stack layout, large model: ; [bp+0] old bp ; [bp+2] return offset ; [bp+4] return segment ; [bp+6] z offset ; [bp+8] z segment ; [bp+10] q offset ; [bp+12] q segment ; [bp+14] nmbr cli mov cx, [bp+14] or cx, cx jz xmem_done push ds push si push di pushf lds si, dword ptr [bp+10] les di, dword ptr [bp+6] cmp di, si jl xmem_forward std dec cx add di, cx add si, cx inc cx jmp xmem_copy xmem_forward: cld xmem_copy: rep movsb popf pop di pop si pop ds xmem_done: pop bp sti ret _xmemmove endp _IPXopen_socket proc far push bp mov bp, sp push ds push si push di ; int IPXopen_socket(UI sock, int live) mov ax, [bp+8] ; live mov dx, [bp+6] ; sock mov bx, @data mov ds, bx mov bx, 0 call dword ptr enterIPX cmp al, 0FFh jne ipxopen_not_already mov ax, -1 ; socket already open jmp ipxopen_done ipxopen_not_already: cmp al, 0FEh jne ipxopen_ok mov ax, -2 ; socket table full jmp ipxopen_done ipxopen_ok: mov ax, dx ipxopen_done: pop di pop si pop ds pop bp ret _IPXopen_socket endp _IPXclose_socket proc far push bp mov bp, sp push ds push si push di ; void IPXclose_socket(UI sock) mov dx, [bp+6] mov bx, @data mov ds, bx mov bx, 1 call dword ptr enterIPX pop di pop si pop ds pop bp ret _IPXclose_socket endp _IPXlisten proc far push bp mov bp, sp push ds push si push di ; int IPXlisten(ECB *ecb) les si, dword ptr [bp+6] mov bx, @data mov ds, bx mov bx, 4 call dword ptr enterIPX pop di pop si pop ds pop bp mov ah, 0 ret _IPXlisten endp _Net_Call proc far push bp mov bp, sp ; int Net_Call(UI func, void *req, void *repl) ; [bp+6] func ; [bp+8] req offset ; [bp+10] req segment ; [bp+12] repl offset ; [bp+14] repl segment mov ax, [bp+6] push ds push si push di pushf lds si, dword ptr [bp+8] les di, dword ptr [bp+12] int 21h popf pop di pop si pop ds pop bp mov ah, 0 ret _Net_Call endp ; int Net_Call_VLM_Raw(UI ax, UI bx, UI cx, UI dx, ; void *req, void *repl, ; UI p1, UI p2, UI p3) ; ; Experimental VLM entry caller. ; INT 2F AX=7A20 returns ES:BX = VLM entry if AX == 0000. ; ; Register setup for VLM entry: ; AX, BX, CX, DX from function args ; DS:SI = req ; ES:DI = repl ; ; Extra stack args pushed before calling VLM entry: ; p3, p2, p1 ; ; For NWCREQUEST/VLM test: ; AX=function ; BX=numReqFrags ; CX=connid ; DX=numReplyFrags ; DS:SI=reqFragList ; ES:DI=replyFragList ; p1=6, p2=20h, p3=0 _Net_Call_VLM_Raw 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 vlm_raw_found mov ax, 88FFh jmp short vlm_raw_done vlm_raw_found: ; save VLM entry ES:BX in stack locals mov [bp-4], bx mov ax, es mov [bp-2], ax ; load caller-requested registers mov ax, [bp+6] mov bx, [bp+8] mov cx, [bp+10] mov dx, [bp+12] lds si, dword ptr [bp+14] les di, dword ptr [bp+18] push word ptr [bp+26] push word ptr [bp+24] push word ptr [bp+22] call dword ptr [bp-4] vlm_raw_done: pop es pop di pop si pop ds mov sp, bp pop bp ret _Net_Call_VLM_Raw endp ; int C32_LoadNios_Probe(UI axfunc, void *outbuf) ; ; 16-bit object, but captures 32-bit ESI and ECX using manual 386 opcodes. ; This keeps the OMF/linker in 16-bit mode while still reading Client32/NIOS ; values returned by: ; INT 2F AX=D8C1 ; ; outbuf: ; +00 word AX after INT 2F ; +02 dword ESI after INT 2F ; +06 dword ECX after INT 2F ; +0A word BX ; +0C word CX low ; +0E word DX ; +10 word SI low ; +12 word DS ; +14 word ES _C32_LoadNios_Probe proc far push bp mov bp, sp push ds push es push si push di ; xor ecx, ecx db 66h, 33h, 0C9h ; xor esi, esi db 66h, 33h, 0F6h mov ax, [bp+6] int 2Fh push ds push es push si push cx push bx push dx push ax les di, dword ptr [bp+8] ; restore AX result into AX and store word at out+0 pop ax mov es:[di+0], ax ; Store ESI dword at es:[di+2]. ; Encoding: ES override + operand-size prefix + MOV r/m32,r32 ; mov es:[di+02], esi = 26 66 89 75 02 db 26h, 66h, 89h, 75h, 02h ; Store ECX dword at es:[di+6]. ; mov es:[di+06], ecx = 26 66 89 4Dh 06 db 26h, 66h, 89h, 4Dh, 06h pop dx pop bx pop cx mov es:[di+10], bx mov es:[di+12], cx mov es:[di+14], dx pop ax ; saved SI mov es:[di+16], ax pop ax ; saved ES pop bx ; saved DS mov es:[di+18], bx mov es:[di+20], ax pop di pop si pop es pop ds pop bp xor ah, ah ret _C32_LoadNios_Probe endp ; int C32_GetFunc_Probe(char *name, void *outbuf) ; ; 16-bit OMF Client32 function resolver probe. ; This mimics C32BEGINUSE for one function name: ; INT 2F AX=D8C1 ; save ESI as far pointer to __Nios+8 function resolver ; push name segment ; push name offset ; push 0 ; push 0 ; call far [ESI] ; add sp,8 ; ; outbuf: ; +00 word load AX from INT2F ; +02 dword ESI from INT2F ; +06 dword ECX from INT2F ; +0A word resolver return AX ; +0C word resolver return DX ; +0E word BX ; +10 word CX _C32_GetFunc_Probe proc far push bp mov bp, sp sub sp, 4 push ds push es push si push di ; clear ECX/ESI db 66h, 33h, 0C9h db 66h, 33h, 0F6h mov ax, 0D8C1h int 2Fh ; save ESI dword to [bp-4] db 66h, 89h, 76h, 0FCh push ax ; save load AX ; call resolver only if AX == 0 or ax, ax jne c32get_store_fail push word ptr [bp+8] ; name segment push word ptr [bp+6] ; name offset push 0 push 0 call dword ptr [bp-4] add sp, 8 jmp short c32get_store c32get_store_fail: xor dx, dx xor ax, ax c32get_store: push dx push ax les di, dword ptr [bp+10] pop ax ; resolver AX pop dx ; resolver DX pop bx ; load AX saved in BX temporarily mov es:[di+0], bx ; Store ESI dword at out+2: ES override + operand prefix db 26h, 66h, 89h, 75h, 02h ; Store ECX dword at out+6 db 26h, 66h, 89h, 4Dh, 06h mov es:[di+10], ax mov es:[di+12], dx mov es:[di+14], bx mov es:[di+16], cx pop di pop si pop es pop ds mov sp, bp pop bp xor ah, ah ret _C32_GetFunc_Probe endp ; int C32_CallVersion_Nios_Probe(void *outbuf) ; ; Safe Client32 version call using the exact d32wrap convention: ; 1) INT 2F AX=D8C1 ; 2) use ESI resolver to resolve "CLIENT32GetVersion" ; 3) call ECX trampoline, not the function pointer directly: ; push 0 ; push 0 ; push fn_seg ; push fn_off ; call ECX ; add sp,8 ; ; outbuf: ; +00 load AX ; +02 resolver off ; +04 resolver seg ; +06 trampoline off ; +08 trampoline seg ; +0A fn off ; +0C fn seg ; +0E call AX ; +10 call DX ; +12 flags _C32_CallVersion_Nios_Probe proc far push bp mov bp, sp sub sp, 12 push ds push es push si push di pushf ; clear ECX/ESI db 66h, 33h, 0C9h db 66h, 33h, 0F6h mov ax, 0D8C1h int 2Fh ; save ESI resolver at [bp-4] db 66h, 89h, 76h, 0FCh ; save ECX trampoline at [bp-8] db 66h, 89h, 4Eh, 0F8h push ax ; load AX for output or ax, ax jne c32ver_fail push cs push offset c32ver_name push 0 push 0 call dword ptr [bp-4] add sp, 8 ; resolver returns DX:AX function pointer mov [bp-12], ax mov [bp-10], dx or ax, dx je c32ver_fail ; d32wrap _CLIENT32GetVersion convention: push 0 push 0 push word ptr [bp-10] push word ptr [bp-12] call dword ptr [bp-8] add sp, 8 pushf push dx push ax jmp short c32ver_store c32ver_fail: xor dx, dx xor ax, ax pushf push dx push ax c32ver_store: les di, dword ptr [bp+6] pop ax ; call AX pop dx ; call DX pop bx ; flags pop cx ; load AX mov es:[di+0], cx mov cx, word ptr [bp-4] mov es:[di+2], cx mov cx, word ptr [bp-2] mov es:[di+4], cx mov cx, word ptr [bp-8] mov es:[di+6], cx mov cx, word ptr [bp-6] mov es:[di+8], cx mov cx, word ptr [bp-12] mov es:[di+10], cx mov cx, word ptr [bp-10] mov es:[di+12], cx mov es:[di+14], ax mov es:[di+16], dx mov es:[di+18], bx popf pop di pop si pop es pop ds mov sp, bp pop bp xor ah, ah ret c32ver_name db 'CLIENT32GetVersion',0 _C32_CallVersion_Nios_Probe endp ; int C32_MapLock_Probe(void *ptr, UI len, void *outbuf) ; ; Probe d32wrap.o __MapLockFlat / __UnlockFlat: ; INT 2F AX=D8C1 ; ESI resolver returned by D8C1 is used with command 2 and 3: ; push len_hi ; push len_lo ; push seg ; push off ; push 0 ; push 2 ; call ESI ; returns flat DX:AX ; ; push len_hi ; push len_lo ; push flat_hi ; push flat_lo ; push 0 ; push 3 ; call ESI ; unlock ; ; outbuf: ; +00 load AX ; +02 ESI off ; +04 ESI seg ; +06 map AX low ; +08 map DX high ; +0A unlock AX ; +0C unlock DX _C32_MapLock_Probe proc far push bp mov bp, sp sub sp, 8 push ds push es push si push di ; clear ECX/ESI db 66h, 33h, 0C9h db 66h, 33h, 0F6h mov ax, 0D8C1h int 2Fh ; save ESI resolver at [bp-4] db 66h, 89h, 76h, 0FCh push ax ; load AX or ax, ax jne mapflat_fail ; MapLockFlat(ptr, len) push 0 push word ptr [bp+10] ; len push word ptr [bp+8] ; ptr seg push word ptr [bp+6] ; ptr off push 0 push 2 call dword ptr [bp-4] add sp, 0cH ; save mapped flat DX:AX at [bp-8] mov word ptr [bp-8], ax mov word ptr [bp-6], dx ; UnlockFlat(flat, len) push 0 push word ptr [bp+10] ; len push dx push ax push 0 push 3 call dword ptr [bp-4] add sp, 0cH jmp short mapflat_store mapflat_fail: xor dx, dx xor ax, ax mov word ptr [bp-8], ax mov word ptr [bp-6], dx mapflat_store: les di, dword ptr [bp+12] mov bx, ax ; unlock AX mov cx, dx ; unlock DX pop ax ; load AX mov es:[di+0], ax mov ax, word ptr [bp-4] mov es:[di+2], ax mov ax, word ptr [bp-2] mov es:[di+4], ax mov ax, word ptr [bp-8] mov es:[di+6], ax mov ax, word ptr [bp-6] mov es:[di+8], ax mov es:[di+10], bx mov es:[di+12], cx pop di pop si pop es pop ds mov sp, bp pop bp xor ah, ah ret _C32_MapLock_Probe endp end