!************************************************************************** !* !* Network driver interface for netboot bootrom !* !* Module: ndisinit.S !* Purpose: Load and initialize the NDIS driver interface !* Entries: drv_load !* !************************************************************************** !* !* 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: ndisinit.S,v 1.4 2003/01/25 23:29:41 gkminix Exp $ !* ! !************************************************************************** ! ! Include assembler macros: ! #include #include #include #include #include "ndispriv.inc" #include "ndisdos.inc" ! !************************************************************************** ! ! BSS segment: ! .bss ! start BSS segment extrn _end_of_bss extrn mac_cct .comm irqnum,2 ! hardware IRQ number ! !************************************************************************** ! ! Start code segment. ! .text public drv_load ! define entry points ! Extern routines of the NDIS interface extern mac_bind ! External routines of the protocol manager extrn pm_init ! External routines of the DOS simulator extrn initdos extrn cleandos extrn loadprog extrn runprog extrn dos4A ! General library external routines extrn prnchar extrn prnstr extrn prnword extrn intsave extrn intrestore extrn intchanged extrn chkhwint ! !************************************************************************** ! ! Load and initialize the NDIS driver interface. When an error ! occurred, it will print an error message before returning. ! Input: ES:SI - pointer to network driver source ! DX - first usable paragraph for network driver ! Output: AX - PXE error code ! Registers changed: AX, BX, CX, DX, SI, DI, ES ! drv_load: ! Get space for the interrupt table copy on the stack. We can safely ! assume that we have enough stack space here (required are 1024 bytes) ! because the kernel loader already switched to a new stack which should ! be large enough. When normally entering a routine C style, BP gets ! the old stack pointer. Here it gets the new stack pointer. Therefore ! we cant use the penter macro. push bp sub sp,#IDT_SIZE mov bp,sp ! First initialize the protocol manager. The initialization routine gets ! the first available segment in the data area in DX, and the pointer to ! the PROTOCOL.INI image in ES:SI. It has to return the first free segment ! in DX, and a pointer to the first byte after the PROTOCOL.INI image in ! ES:SI. call pm_init ! initialize protocol manager mov bx,#pimsg ! invalid PROTOCOL.INI image jc initF ! Save all interrupts and initialize the DOS simulator. init1: push es push si call intsave ! save interrupts call initdos ! initialize the DOS simulator pop si pop es ! Scan through the list of DOS programs and run each in turn. The binary ! patch program should have stored the number of DOS programs at the first ! byte of the network driver source area. The first program has to be the ! NDIS device driver, which will be initialized. ! Note that these DOS simuator routines print a message in case of an ! error, so we dont have to do it ourselves. ! After all programs have been started, restore all interrupt vectors and ! identify those which have been changed by the packet driver. These will ! be set in the local IDT buffer. Then clean all DOS interrupts from this ! buffer, as the DOS simulator should not be needed anymore. seg es mov cx,word ptr [si] ! get number of DOS programs add si,#2 push cx call loadprog ! load NDIS driver into DOS memory jc init3 call startdrv ! startup driver pop cx mov bx,#drvmsg ! check for error jc initF dec cx jz init5 init2: push cx call loadprog ! load program into DOS memory jc init3 call runprog ! and run it init3: pop cx jnc init4 call intrestore ! in case of error restore all jmp initE ! interrupt vectors init4: loop init2 ! scan through all programs ! Bind the NDIS driver. Unfortunately, some drivers only set the hardware ! interrupt at bind time, not at initialization time. Since we need to ! know the hardware interrupt now and cant allow the driver to set it ! lateron, we have to do the bind now. init5: call mac_bind mov bx,#drvmsg jc initF ! We can now restore all interrupts and cleanup the DOS interrupts. call intrestore ! restore all interrupt vectors jnc init6 ! and save new vectors in IDT buffer mov bx,#chgmsg ! print error message initF: push bx mov bx,#errmsg call prnstr pop bx call prnstr mov bx,#crlf call prnstr initE: mov ax,#PXENV_EXIT_FAILURE jmp init9 init6: call cleandos ! cleanup DOS interrupts ! Now try to find the hardware interrupt in the local interrupt buffer. This ! will also clear the interrupt from the IDT buffer. We have to use our own ! hardware interrupt detection routine, because the corresponding field in ! the MAC Service Specific Characteristics (SSC) table is only available ! at NDIS version 2.0.1 and later. Most drivers still use the older 2.0 ! version, which doesnt define these hardware interrupt detection fields. call chkhwint ! find hardware interrupt mov bx,#hwmsg ! print error message if not IRQ found jcxz initF mov [irqnum],cx ! save hardware IRQ number ! Finally set all those interrupt vectors which have to remain set while the ! packet driver is loaded. Then tell the user that we found something. call intchanged ! identify permanent interrupts mov bx,#fndmsg call prnstr cld push ds lds si,[mac_cct] lea si,[si + CCT_MOD_NAME] ! print module name initA: lodsb or al,al jz initB call prnchar jmp initA initB: pop ds mov bx,#irqmsg call prnstr mov ax,[irqnum] call prnword ! print hardware IRQ number mov bx,#crlf call prnstr xor ax,ax ! return without error init9: add sp,#IDT_SIZE ! restore stack pop bp ret ! Message to tell user that we found something fndmsg: .byte $0D,$0A .asciz "Found NDIS driver " irqmsg: .asciz ", irq " ! Error messages errmsg: .byte $0D,$0A .asciz "NDIS ERROR: " pimsg: .asciz "PROTOCOL.INI invalid" drvmsg: .asciz "invalid driver" hwmsg: .asciz "no hw int" chgmsg: .asciz "too many changed ints" crlf: .byte $0D,$0A,0 ! !************************************************************************** ! ! Call NDIS device initialization routine ! Input: BX - first segment of device driver ! Output: Carry set if error ! Registers changed: AX, BX, CX, DX ! startdrv: penter (DEV0_LENGTH) ! Clear the device request header. push es push ds mov dx,bx mov ax,ss mov es,ax ! put pointer to request header into lea di,[bp - DEV0_LENGTH] ! ES:BX mov bx,di mov cx,#DEV0_LENGTH ! clear device request header xor al,al cld rep stosb ! Setup the device request header with some default values, including the ! last usable segment. According to the specs this should only be necessary ! before calling the device driver initialization routine. However, some ! NDIS drivers already use the device strategy routine for initialization, ! so the device request header has to be setup now. mov ax,dx sub ax,#(PSP_SIZE / 16) + 1 mov cx,ax inc cx mov ds,ax add ax,[mcb_size] inc ax mov byte ptr [bp - DEV0_LENGTH + DEVREQ_LENGTH],#DEV0_LENGTH if DEV_INIT > 0 mov byte ptr [bp - DEV0_LENGTH + DEVREQ_COMMAND],#DEV_INIT endif mov word ptr [bp - DEV0_LENGTH + DEV0_MEMAVAIL + 2],ax mov word ptr [bp - DEV0_LENGTH + DEV0_CMDLINE + 0],#o_psp_cmdl mov word ptr [bp - DEV0_LENGTH + DEV0_CMDLINE + 2],cx mov ds,dx ! Now call the device driver strategy routine with ES:BX pointing to the ! properly setup device request header. push cs #ifdef IS186 push #start1 ! push far return address #else mov ax,#start1 ! push far return address push ax #endif push ds ! push ptr to device strategy routine push word ptr [DEVHDR_STRAT] retf ! call strategy routine ! Call the device initialization routine. The pointer to the device request ! header has already been passed to the device driver, setup with the proper ! operation code. start1: push cs #ifdef IS186 push #start2 ! push far return address #else mov ax,#start2 ! push far return address push ax #endif push ds ! push ptr to device strategy routine push word ptr [DEVHDR_INT] retf ! call device initialization routine ! Check for driver return code. start2: pop ds cmp word ptr [bp - DEV0_LENGTH + DEVREQ_STATUS],#DEVERR_SUCCESS jne start8 ! Determine the last address of the network driver and adjust the memory ! allocation accordingly. mov es,cx mov bx,[bp - DEV0_LENGTH + DEV0_FREE + 0] add bx,#$000F rcr bx,#1 ! adjust last address to paragraph shift (shr,bx,3) ! boundary add bx,[bp - DEV0_LENGTH + DEV0_FREE + 2] sub bx,cx ! compute new size of driver memory jbe start8 ! block in paragraphs call dos4A ! resize the memory block jnc start9 start8: stc ! in case of error return with carry set start9: pop es pleave ret ! !************************************************************************** ! end