!************************************************************************** !* !* Network driver interface for netboot bootrom !* !* Module: protman.S !* Purpose: Protocol manager support for NDIS interface !* Entries: pm_init !* !************************************************************************** !* !* Copyright (C) 1998-2003 Gero Kuhlmann !* !* This program is free software; you can redistribute it and/or modify !* it under the terms of the GNU General Public License as published by !* the Free Software Foundation; either version 2 of the License, or !* any later version. !* !* This program is distributed in the hope that it will be useful, !* but WITHOUT ANY WARRANTY; without even the implied warranty of !* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the !* GNU General Public License for more details. !* !* You should have received a copy of the GNU General Public License !* along with this program; if not, write to the Free Software !* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. !* !* $Id: protman.S,v 1.5 2003/01/25 23:29:42 gkminix Exp $ !* ! !************************************************************************** ! ! Include assembler macros: ! #include #include #include "ndispriv.inc" #include "ndisdos.inc" ! !************************************************************************** ! ! BSS segment: ! .bss extrn alt_handler ! alternative DOS function handler .lcomm pi_seg,2 ! segment of PROTOCOL.INI image .lcomm pi_size,2 ! size of PROTOCOL.INI image .comm mac_cct,4 ! far ptr to MAC CCT ! !************************************************************************** ! ! Data segment: ! .data pmfile: .asciz "protman$" ! device name of protocol manager ! !************************************************************************** ! ! Start code segment. ! .text public pm_init ! define entry points extrn txtseg ! !************************************************************************** ! ! Initialize the protocol manager support for the NDIS interface. This ! involves copying the PROTOCOL.INI image into place, adjust all far ! pointers in it and set our own DOS function handler. ! Input: ES:SI - pointer to PROTOCOL.INI image ! DX - first usable paragraph in data area ! Output: ES:SI - pointer to first byte after PROTOCOL.INI image ! DX - first usable paragraph after PROTOCOL.INI image ! Output: Carry flag if fatal error ! Registers changed: AX, BX, CX, DX, SI, DI, ES ! pm_init: ! First copy the PROTOCOL.INI image into our private data segment cld mov [pi_seg],dx ! save segment to new PROTOCOL.INI image push ds push es mov ax,es ! set DS:SI to source image mov es,dx ! set ES:DI to destination area mov ds,ax xor di,di lodsw ! get size of PROTOCOL.INI image mov cx,ax rep movsb ! copy PROTOCOL.INI image mov bx,es ! save ES:DI for later mov cx,di add di,#$000F ! adjust end address to paragraph rcr di,#1 shift (shr,di,3) ! boundary add dx,di ! compute first segment after new image pop es ! ES:SI and DX now contain the return pop ds ! values mov [pi_size],ax ! save size of PROTOCOL.INI image seg cs cmp dx,[txtseg] ! check if image is too large jae pmini8 ! Now set all far pointers in the new image. makerom placed only the ! offsets into the pointer variables. At this point, BX contains the ! offset to the first byte after the PROTOCOL.INI image. We have to ! leave ES:SI and DX unchanged here. push ds mov ds,bx ! set DS:DI to beginning of new image xor di,di ! copy pmini1: cmp di,cx ! check if past end of new image, ja pmini7 ! should never happen mov bx,[di + 0] ! get offset to next module header or bx,bx jz pmini2 ! skip adjusting segment for last header mov [di + 2],ds ! save new segment pmini2: mov ax,[di + 4] ! get offset to previous module header or ax,ax jz pmini3 ! skip adjusting if first header mov [di + 6],ds ! save new segment pmini3: add di,#24 ! set DS:DI to first keyword entry push bx push cx or bx,bx ! set end offset of current module jz pmini4 mov cx,bx pmini4: cmp di,cx ! check if past end of current module ja pmini6 mov bx,[di + 0] ! get offset to next keyword or bx,bx jz pmini5 mov [di + 2],ds ! save new segment pmini5: mov ax,[di + 4] ! get offset to previous keyword or ax,ax jz pminiA mov [di + 6],ds ! save new segment pminiA: mov di,bx ! go to next keyword or di,di jnz pmini4 ! check if at end of keyword list pop cx ! restore values for current module pop bx mov di,bx ! go to next module header or di,di jnz pmini1 ! check if at end of module header list pop ds ! Thats it. We can now set the alternative DOS handler and return without ! error. mov word ptr [alt_handler],#dos_handle clc jmp pmini9 pmini6: pop cx ! clear stack before returning pop bx pmini7: pop ds pmini8: stc ! return with an error pmini9: ret ! !************************************************************************** ! ! Our private DOS function handler. It gets called exactly like any function ! in the DOS simulator. ! Input: AH - function code ! DS - our own data segment ! SS:SP - our own DOS stack ! BP - offset to DOS stack local variables ! other registers depend on the function called ! Output: depends on function called ! Registers changed: depends on function called ! dos_handle: ! First check for open function. We only accept it if its for the protocol ! manager device. cmp ah,#DOSFN_OPEN ! check for open function jne doshd4 push ax push es push di push si mov es,old_ds[bp] ! set DS:SI to name of protocol mov di,dx ! manager device mov si,#pmfile ! set ES:DI to function argument doshd1: seg es mov al,[di] ! load next character cmp al,#0x41 jb doshd2 cmp al,#0x5A ! convert it to lower case ja doshd2 add al,#0x20 doshd2: cmp al,[si] ! compare it with device name jne doshd3 inc si inc di ! goto next character or al,al ! check if at end of string jnz doshd1 doshd3: pop si pop di pop es pop ax jnz doshd9 ! filename not found mov ax,#PM_HANDLE ! return device handle jmp doshd8 ! return with carry flag cleared ! Now handle close request. We only handle it if its for our protocol manager ! device. Actually, we dont have to do anything here. doshd4: cmp ah,#DOSFN_CLOSE ! check for close function jne doshd6 cmp bx,#PM_HANDLE ! if not for protman device, let jne doshd9 ! DOS simulator handle the request jmp doshd8 ! otherwise return without error ! Finally handle IOTCL request. We also handle this request only if its for ! the protocol manager device doshd6: cmp ah,#DOSFN_IOCTL ! check for IOCTL function jne doshd9 cmp bx,#PM_HANDLE ! if not for protman device, let jne doshd9 ! DOS simulator handle the request jmp ioctl ! We handled the function request. In order to return to the DOS simulators ! exit routine, we have to rmove our return address and the address of the ! DOS simulator internal function from the stack. Then we can use the return ! instruction to get back to the simulator. doshd7: add sp,#4 stc ! return with error ret doshd8: add sp,#4 clc ! return without error doshd9: ret ! return to DOS simulator ! Finally handle IOCTL requests. We put this at the end of the routine ! in order to allow for short jumps to the return labels. ioctl: cmp al,#IOCTL_GETINFO jne doioc1 mov dx,#PM_DEVINFO ! get device driver info jmp doshd8 doioc1: cmp al,#IOCTL_RDCHAR jne doioc4 cmp cx,#PMREQ_SIZE ! check for correct request header size je doioc3 mov ax,#ERR_INVDATA ! return with error jmp doshd7 doioc3: push ax ! since the protocol manager is only push bx ! required to save SI, DI and BP, we push cx ! have to care for all other registers push dx push old_ds[bp] ! push address of request block push dx push ds ! push protocol manager data segment push cs ! protocol manager returns with far ret call protman ! call protocol manager pop dx pop cx ! restore registers pop bx pop ax jmp doshd8 ! return without error doioc4: mov ax,#ERR_NOFN ! all other functions are not supported jmp doshd7 ! !************************************************************************** ! ! This is the protocol manager function dispatcher. It gets called by ! a far call either from the DOS handler or directly from a NDIS module ! in pascal calling style. ! Input: 1. Arg - far pointer to protocol manager request header ! 2. Arg - protocol manager data segment ! Output: AX - error code ! Registers changed: AX, BX, CX, DX ! protman: push bp ! setup standard stack frame mov bp,sp push ds push es push di les di,[bp + 8] ! get pointer to request structure mov ds,[bp + 6] ! get protocol manager data segment ! Check for correct function number and call appropriate function handler seg es mov bx,[di + PMREQ_OPCODE] cmp bx,#PMREQ_MINFN ! check for function number being in jb protm8 ! the correct range cmp bx,#PMREQ_MAXFN ja protm8 if PMREQ_MINFN = 1 dec bx else sub bx,#PMREQ_MINFN endif shl bx,#1 ! get function handler address #ifdef IS186 push #protm9 ! push return address #else mov ax,#protm9 push ax #endif seg cs jmp jmptab[bx] ! call function handler protm8: mov ax,#NDISERR_FUNCTION ! return with invalid function error protm9: seg es mov [di + PMREQ_STATUS],ax ! set status of function call pop di pop es ! restore registers and return to caller pop ds pop bp retf 6 ! return with removing the arguments ! Function handler jump table jmptab: .word pmfunc1 .word pmfunc2 .word unused .word pmfunc4 .word unused .word unused .word unused .word unused .word unused .word pmfunc10 ! !************************************************************************** ! ! Unimplemented functions: ! ! 3 - BindAndStart: only called by application program which doesnt exist ! in the bootrom ! 5 - GetProtocolIniPath: we dont have a real PROTOCOL.INI file and ! therefore no valid path ! 6 - RegisterProtocolManagerInfo: only used in dynamic mode, which we ! dont implement ! 7 - InitAndRegister: only used with OS/2 ! 8 - UnbindAndStop: only used in dynamic mode, called by application ! program ! 9 - BindStatus: not enabled per NDIS 2.0.1 (assuming BINDSTATUS=NO) ! ! Input: ES:DI - pointer to protocol manager request header ! Output: AX - error code ! Registers changed: AX ! unused: mov ax,#NDISERR_FUNCTION ! simply return with error ret ! !************************************************************************** ! ! Protocol manager function 1: GetProtocolManagerInfo ! Input: ES:DI - pointer to protocol manager request header ! Output: AX - error code ! Registers changed: AX ! pmfunc1: seg es mov word ptr [di + PMREQ_PTR1 + 0],#0 ! save pointer to mov ax,pi_seg ! PROTOCOL.INI image seg es ! into request header mov word ptr [di + PMREQ_PTR1 + 2],ax seg es ! save NDIS version no mov word ptr [di + PMREQ_WORD1],#NDIS_MAJOR_VER + (NDIS_MINOR_VER * 256) xor ax,ax ! return without error ret ! !************************************************************************** ! ! Protocol manager function 2: RegisterModule ! Input: ES:DI - pointer to protocol manager request header ! Output: AX - error code ! Registers changed: AX ! pmfunc2: push es push di ! The only module which we want to know about is the first MAC. So first ! check if a MAC has already been registered, and that we have indeed a ! MAC request here. Then simply save the CCT address. We dont need the ! bindings list address, as a MAC cant have a lower bindings list. mov ax,word ptr [mac_cct + 0] or ax,word ptr [mac_cct + 2] mov ax,#NDISERR_REGISTERED jnz pmf29 seg es les di,[di + PMREQ_PTR1] ! load pointer to CCT mov ax,#NDISERR_PARAM seg es mov dx,word ptr [di + CCT_FUNCTION_FLAGS] test dx,#MODFUNC_DYN_BIND ! dynamic binding not allowed jnz pmf29 seg es cmp byte ptr [di + CCT_UPPER_LEVEL],#PROT_MAC jne pmf29 seg es cmp byte ptr [di + CCT_LOWER_LEVEL],#PROT_PHYS jne pmf29 seg es cmp byte ptr [di + CCT_UPPER_TYPE],#TYPE_MAC jne pmf29 ! Save module ID into CCT and save MAC CCT address seg es mov word ptr [di + CCT_MODULE_ID],#MODID_MAC mov word ptr [mac_cct + 0],di mov word ptr [mac_cct + 2],es xor ax,ax ! return without error pmf29: pop di pop es ret ! !************************************************************************** ! ! Protocol manager function 4: GetProtocolManagerLinkage ! Input: ES:DI - pointer to protocol manager request header ! Output: AX - error code ! Registers changed: AX ! pmfunc4: seg es mov [di + PMREQ_PTR1 + 0],#protman ! save far pointer to protocol seg es ! manager entry point mov [di + PMREQ_PTR1 + 2],cs seg es mov [di + PMREQ_WORD1],ds ! save protocol manager data xor ax,ax ! segment, and return without ret ! error ! !************************************************************************** ! ! Protocol manager function 10: RegisterStatus ! Input: ES:DI - pointer to protocol manager request header ! Output: AX - error code ! Registers changed: AX ! pmfunc10: cld push ds push es push si push di mov ax,#NDISERR_REGISTERED ! return with error if name found lds si,[mac_cct] ! load MAC CCT pointer mov dx,ds or dx,si ! check if CCT pointer is valid jz pmf108 add si,#CCT_MOD_NAME ! let DS:SI point to module name seg es les di,[di + PMREQ_PTR2] ! load module name pointer mov cx,#16 rep cmpsb ! compare both strings je pmf109 ! names are identical seg es mov dl,[di - 1] ! check if last byte is the terminating or dl,[si - 1] ! zero in both strings jz pmf109 pmf108: xor ax,ax ! name not found -> no error pmf109: pop di pop si pop es pop ds ret ! !************************************************************************** ! end