diff --git a/kernel/trunk/network/eth_drv/arp.inc b/kernel/trunk/network/eth_drv/arp.inc new file mode 100644 index 0000000000..94ac376b62 --- /dev/null +++ b/kernel/trunk/network/eth_drv/arp.inc @@ -0,0 +1,546 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; ARP.INC +;; +;; Address Resolution Protocol +;; +;; Last revision: 10.11.2006 +;; +;; This file contains the following: +;; arp_table_manager - Manages an ARPTable +;; arp_request - Sends an ARP request on the ethernet +;; arp_handler - Called when an ARP packet is received +;; +;; Changes history: +;; 22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net +;; 11.11.2006 - [Johnny_B] and [smb] +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +ARP_NO_ENTRY equ 0 +ARP_VALID_MAPPING equ 1 +ARP_AWAITING_RESPONSE equ 2 +ARP_RESPONSE_TIMEOUT equ 3 + +struc ARP_ENTRY ;=14 bytes +{ .IP dd ? ;+00 + .MAC dp ? ;+04 + .Status dw ? ;+10 + .TTL dw ? ;+12 : ( in seconds ) +} + +virtual at 0 + ARP_ENTRY ARP_ENTRY +end virtual + +; The TTL field is decremented every second, and is deleted when it +; reaches 0. It is refreshed every time a packet is received +; If the TTL field is 0xFFFF it is a static entry and is never deleted +; The status field can be the following values: +; 0x0000 entry not used +; 0x0001 entry holds a valid mapping +; 0x0002 entry contains an IP address, awaiting ARP response +; 0x0003 No response received to ARP request. +; The last status value is provided to allow the network layer to delete +; a packet that is queued awaiting an ARP response + + +; The follow is the ARP Table. +; This table must be manually updated and the kernel recompilied if +; changes are made to it. +; Empty entries are filled with zeros + +ARP_ENTRY_SIZE equ 14 ; Number of bytes per entry +ARP_TABLE_SIZE equ 20 ; Size of table +ARP_TABLE_ENTRIES equ 0 ; Number of static entries in the table + +;TO ADD A STATIC ENTRY, DONT FORGET, PUT "ARPTable" from "uglobal" to "iglobal"!!! +;AND ALSO - IP and MAC have net byte-order, BUT STATUS AND TTL HAVE A MIRROR BYTE-ORDER!!! +uglobal + ARPTable: +;example, static entry -> db 11,22,33,44, 0x11,0x22,0x33,0x44,0x55,0x66, 0x01,0x00, 0xFF,0xFF + times ( ARP_TABLE_SIZE - ARP_TABLE_ENTRIES ) * ARP_ENTRY_SIZE db 0 +endg + +iglobal + NumARP: dd ARP_TABLE_ENTRIES + ARPTable_ptr dd ARPTable ;pointer to ARPTable +endg + +ARP_REQ_OPCODE equ 0x0100 ;request +ARP_REP_OPCODE equ 0x0200 ;reply + +struc ARP_PACKET +{ .HardwareType dw ? ;+00 + .ProtocolType dw ? ;+02 + .HardwareSize db ? ;+04 + .ProtocolSize db ? ;+05 + .Opcode dw ? ;+06 + .SenderMAC dp ? ;+08 + .SenderIP dd ? ;+14 + .TargetMAC dp ? ;+18 + .TargetIP dd ? ;+24 +} + +virtual at 0 + ARP_PACKET ARP_PACKET +end virtual + + + +;*************************************************************************** +; Function +; arp_table_manager [by Johnny_B] +; +; Description +; Does a most required operations with ARP-table +; IN: +; Operation: see Opcode's constants below +; Index: Index of entry in the ARP-table +; Extra: Extra parameter for some Opcodes +; OUT: +; EAX = Returned value depends on opcodes, more detailed see below +; +;*************************************************************************** +;Opcode's constants +ARP_TABLE_ADD equ 1 +ARP_TABLE_DEL equ 2 +ARP_TABLE_GET equ 3 +ARP_TABLE_GET_ENTRIES_NUMBER equ 4 +ARP_TABLE_IP_TO_MAC equ 5 +ARP_TABLE_TIMER equ 6 + +;Index's constants +EXTRA_IS_ARP_PACKET_PTR equ 0 ;if Extra contain pointer to ARP_PACKET +EXTRA_IS_ARP_ENTRY_PTR equ -1 ;if Extra contain pointer to ARP_ENTRY + +align 4 +proc arp_table_manager stdcall uses ebx esi edi ecx edx,\ + Opcode:DWORD,Index:DWORD,Extra:DWORD + + mov ebx, dword[ARPTable_ptr] ;ARPTable base + mov ecx, dword[NumARP] ;ARP-entries counter + + mov eax, dword[Opcode] + cmp eax, ARP_TABLE_TIMER + je .timer + cmp eax, ARP_TABLE_ADD + je .add + cmp eax, ARP_TABLE_DEL + je .del + cmp eax, ARP_TABLE_GET + je .get + cmp eax, ARP_TABLE_IP_TO_MAC + je .ip_to_mac + cmp eax, ARP_TABLE_GET_ENTRIES_NUMBER + je .get_entries_number + jmp .exit ;if unknown opcode + + +;;BEGIN TIMER +;;Description: it must be callback every second. It is responsible for removing expired routes. +;;IN: Operation: ARP_TABLE_TIMER +;; Index: must be zero +;; Extra: must be zero +;;OUT: +;; EAX=not defined +;; +.timer: + test ecx, ecx + jz .exit ;if NumARP=0 nothing to do + sub ecx, ARP_TABLE_ENTRIES ;ecx=dynamic entries number + jz .exit ;if NumARP=number of static entries then exit + + add ebx, ARP_TABLE_ENTRIES*ARP_ENTRY_SIZE ;ebx=dynamic entries base + + .timer_loop: + movsx esi, word [ebx + ARP_ENTRY.TTL] + cmp esi, 0xFFFFFFFF + je .timer_loop_end ;if TTL==0xFFFF then it's static entry + + test esi, esi + jnz .timer_loop_end_with_dec ;if TTL!=0 + + ; Ok, TTL is 0 + ;if Status==AWAITING_RESPONSE and TTL==0 + ;then we have to change it to ARP_RESPONSE_TIMEOUT + cmp word [ebx + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE + jne @f + + mov word [ebx + ARP_ENTRY.Status], ARP_RESPONSE_TIMEOUT + mov word [ebx + ARP_ENTRY.TTL], word 0x000A ;10 sec + jmp .timer_loop_end + + @@: + ;if TTL==0 and Status==VALID_MAPPING, we have to delete it + ;if TTL==0 and Status==RESPONSE_TIMEOUT, delete too + mov esi, dword[NumARP] + sub esi, ecx ;esi=index of entry, will be deleted + stdcall arp_table_manager,ARP_TABLE_DEL,esi,0 ;opcode,index,extra + jmp .timer_loop_end + + + .timer_loop_end_with_dec: + dec word [ebx + ARP_ENTRY.TTL] ;decrease TTL + .timer_loop_end: + add ebx, ARP_ENTRY_SIZE + loop .timer_loop + + jmp .exit +;;END TIMER + +;;BEGIN ADD +;;Description: it adds an entry in the table. If ARP-table already +;; contains same IP, it will be updated. +;;IN: Operation: ARP_TABLE_ADD +;; Index: specifies what contains Extra-parameter +;; Extra: if Index==EXTRA_IS_ARP_PACKET_PTR, +;; then Extra contains pointer to ARP_PACKET, +;; otherwise Extra contains pointer to ARP_ENTRY +;;OUT: +;; EAX=index of entry, that has been added +;; +.add: + + sub esp, ARP_ENTRY_SIZE ;Allocate ARP_ENTRY_SIZE byte in stack + + mov esi, [Extra] ;pointer + mov edi, [Index] ;opcode + + cmp edi, EXTRA_IS_ARP_PACKET_PTR + je .arp_packet_to_entry ;if Extra contain ptr to ARP_PACKET and we have to form arp-entry + ;else it contain ptr to arp-entry + + cld + ; esi already has been loaded + mov edi, esp ;ebx + eax=ARPTable_base + ARP-entry_base(where we will add) + mov ecx,ARP_ENTRY_SIZE/2 ;ARP_ENTRY_SIZE must be even number!!! + rep movsw ;copy + jmp .search + + .arp_packet_to_entry: + mov edx, dword[esi + ARP_PACKET.SenderIP] ;esi=base of ARP_PACKET + mov [esp + ARP_ENTRY.IP], edx + + cld + lea esi, [esi + ARP_PACKET.SenderMAC] + lea edi, [esp + ARP_ENTRY.MAC] + movsd + movsw + mov word[esp + ARP_ENTRY.Status], ARP_VALID_MAPPING ; specify the type - a valid entry + mov word[esp + ARP_ENTRY.TTL], 0x0E10 ; = 1 hour + + .search: + mov edx, dword[esp + ARP_ENTRY.IP] ;edx=IP-address, which we'll search + mov ecx, dword[NumARP] ;ecx=ARP-entries counter + jecxz .add_to_end ;if ARP-entries number == 0 + imul eax, ecx, ARP_ENTRY_SIZE ;eax=current table size(in bytes) + @@: + sub eax, ARP_ENTRY_SIZE + cmp dword[ebx + eax + ARP_ENTRY.IP], edx + loopnz @b + jz .replace ; found, replace existing entry, ptr to it is in eax + + .add_to_end: + ;else add to end + or eax,-1 ;set eax=0xFFFFFFFF if adding is impossible + mov ecx, dword[NumARP] + cmp ecx, ARP_TABLE_SIZE + je .add_exit ;if arp-entries number is equal to arp-table maxsize + + imul eax, dword[NumARP], ARP_ENTRY_SIZE ;eax=ptr to end of ARPTable + inc dword [NumARP] ;increase ARP-entries counter + + .replace: + cld + mov esi, esp ;esp=base of ARP-entry, that will be added + lea edi, [ebx + eax] ;ebx + eax=ARPTable_base + ARP-entry_base(where we will add) + mov ecx,ARP_ENTRY_SIZE/2 ;ARP_ENTRY_SIZE must be even number!!! + rep movsw + + mov ecx, ARP_ENTRY_SIZE + xor edx, edx ;"div" takes operand from EDX:EAX + div ecx ;eax=index of entry, which has been added + +.add_exit: + add esp, ARP_ENTRY_SIZE ;free stack + jmp .exit +;;END ADD + +;;BEGIN DEL +;;Description: it deletes an entry in the table. +;;IN: Operation: ARP_TABLE_DEL +;; Index: index of entry, that should be deleted +;; Extra: must be zero +;;OUT: +;; EAX=not defined +;; +.del: + mov esi, [Index] + imul esi, ARP_ENTRY_SIZE + + mov ecx, (ARP_TABLE_SIZE - 1) * ARP_ENTRY_SIZE + sub ecx, esi + + lea edi, [ebx + esi] ;edi=ptr to entry that should be deleted + lea esi, [edi + ARP_ENTRY_SIZE] ;esi=ptr to next entry + + shr ecx,1 ;ecx/2 => ARP_ENTRY_SIZE MUST BE EVEN NUMBER! + cld + rep movsw + + dec dword[NumARP] ;decrease arp-entries counter + jmp .exit +;;END DEL + +;;BEGIN GET +;;Description: it reads an entry of table into buffer. +;;IN: Operation: ARP_TABLE_GET +;; Index: index of entry, that should be read +;; Extra: pointer to buffer for reading(size must be equal to ARP_ENTRY_SIZE) +;;OUT: +;; EAX=not defined +;; +.get: + mov esi, [Index] + imul esi, ARP_ENTRY_SIZE ;esi=ptr to required ARP_ENTRY + mov edi, [Extra] ;edi=buffer for reading + mov ecx, ARP_ENTRY_SIZE/2 ; must be even number!!! + cld + rep movsw + jmp .exit +;;END GET + +;;BEGIN IP_TO_MAC +;;Description: it gets an IP from Index, scans each entry in the table and writes +;; MAC, that relates to specified IP, into buffer specified in Extra. +;; And if it cannot find an IP-address in the table, it does an ARP-request of that. +;;IN: Operation: ARP_TABLE_IP_TO_MAC +;; Index: IP that should be transformed into MAC +;; Extra: pointer to buffer where will be written the MAC-address. +;;OUT: +;; EAX=ARP table entry status code. +;; If EAX==ARP_NO_ENTRY, IP isn't found in the table and we have sent the request. +;; If EAX==ARP_AWAITING_RESPONSE, we wait the response from remote system. +;; If EAX==ARP_RESPONSE_TIMEOUT, remote system not responds too long. +;; If EAX==ARP_VALID_MAPPING, all is ok, we've got a true MAC. +;; +;; If MAC will equal to a zero, in the buffer. It means, that IP-address was not yet +;; resolved, or that doesn't exist. I recommend you, to do at most 3-5 calls of this +;; function with 1sec delay. sure, only if it not return a valid MAC after a first call. +;; +.ip_to_mac: + + xor eax, eax + mov edi, dword[Extra] + cld + stosd + stosw + + cmp dword[NumARP], 0 + je .ip_to_mac_send_request ;if ARP-table not contain an entries, we have to request IP. + ;EAX will be containing a zero, it's equal to ARP_NO_ENTRY + + ; first, check destination IP to see if it is on 'this' network. + ; The test is: + ; if ( destIP & subnet_mask == stack_ip & subnet_mask ) + ; destination is local + ; else + ; destination is remote, so pass to gateway + + mov eax, [Index] ;eax=required IP + mov esi, eax + and esi, [subnet_mask] + mov ecx, [stack_ip] + and ecx, [subnet_mask] + cmp esi, ecx + je @f ;if we and target IP are located in the same network + mov eax, [gateway_ip] + @@: + + mov ecx, dword[NumARP] + imul esi, ecx, ARP_ENTRY_SIZE ;esi=current ARP-table size + + @@: + sub esi, ARP_ENTRY_SIZE + cmp [ebx + esi], eax ; ebx=ARPTable base + loopnz @b ; Return back if non match + jnz .ip_to_mac_send_request ; and request IP->MAC if none found in the table + + ; Return the entry status in eax + movzx eax, word[ebx + esi + ARP_ENTRY.Status] + + ; esi holds index + cld + lea esi, [ebx + esi + ARP_ENTRY.MAC] + mov edi, [Extra] ;edi=ptr to buffer for write MAC + movsd + movsw + jmp .exit + + .ip_to_mac_send_request: + stdcall arp_request,[Index],stack_ip,node_addr ;TargetIP,SenderIP_ptr,SenderMAC_ptr + mov eax, ARP_NO_ENTRY + jmp .exit + +;;END IP_TO_MAC + +;;BEGIN GET_ENTRIES_NUMBER +;;Description: returns an ARP-entries number in the ARPTable +;;IN: Operation: ARP_TABLE_GET_ENTRIES_NUMBER +;; Index: must be zero +;; Extra: must be zero +;;OUT: +;; EAX=ARP-entries number in the ARPTable + .get_entries_number: + mov eax, dword[NumARP] + jmp .exit +;;END GET_ENTRIES_NUMBER + +.exit: + ret +endp + + +;*************************************************************************** +; Function +; arp_handler +; +; Description +; Called when an ARP packet is received on the ethernet +; Header + Data is in Ether_buffer[] +; It looks to see if the packet is a request to resolve this Hosts +; IP address. If it is, send the ARP reply packet. +; This Hosts IP address is in dword [stack_ip] ( in network format ) +; This Hosts MAC address is in node_addr[6] +; All registers may be destroyed +; +;*************************************************************************** +arp_handler: + ; Is this a REQUEST? + ; Is this a request for My Host IP + ; Yes - So construct a response message. + ; Send this message to the ethernet card for transmission + + stdcall arp_table_manager,ARP_TABLE_ADD,EXTRA_IS_ARP_PACKET_PTR,ETH_FRAME.Data + ARP_PACKET + + inc dword[arp_rx_count] ;increase ARP-packets counter + + cmp word[ETH_FRAME.Data + ARP_PACKET.Opcode], ARP_REQ_OPCODE ; Is this a request packet? + jne .exit ; No - so exit + + mov eax, [stack_ip] + cmp eax, dword[ETH_FRAME.Data + ARP_PACKET.TargetIP] ; Is it looking for my IP address? + jne .exit ; No - so quit now + + ; OK, it is a request for my MAC address. Build the frame and send it + ; We can reuse the packet. + + mov word[ETH_FRAME.Data + ARP_PACKET.Opcode], ARP_REP_OPCODE + + cld + mov esi, ETH_FRAME.Data + ARP_PACKET.SenderMAC + mov edi, ETH_FRAME.Data + ARP_PACKET.TargetMAC + movsd + movsw + + mov esi, ETH_FRAME.Data + ARP_PACKET.SenderIP + mov edi, ETH_FRAME.Data + ARP_PACKET.TargetIP + movsd + + mov esi, node_addr + mov edi, ETH_FRAME.Data + ARP_PACKET.SenderMAC + movsd + movsw + + mov esi, stack_ip + mov edi, ETH_FRAME.Data + ARP_PACKET.SenderIP + movsd + + ; Now, send it! + mov edi, ETH_FRAME.Data + ARP_PACKET.TargetMAC ;ptr to destination MAC address + mov bx, ETHER_ARP ;type of protocol + mov ecx, 28 ;data size + mov esi, ETH_FRAME.Data + ARP_PACKET ;ptr to data + call dword [drvr_transmit] ;transmit packet + + .exit: + ret + + +;*************************************************************************** +; Function +; arp_request [by Johnny_B] +; +; Description +; Sends an ARP request on the ethernet +; IN: +; TargetIP : requested IP address +; SenderIP_ptr : POINTER to sender's IP address(our system's address) +; SenderMAC_ptr : POINTER to sender's MAC address(our system's address) +; OUT: +; EAX=0 (if all is ok), otherwise EAX is not defined +; +; EBX,ESI,EDI will be saved +; +;*************************************************************************** +proc arp_request stdcall uses ebx esi edi,\ + TargetIP:DWORD, SenderIP_ptr:DWORD, SenderMAC_ptr:DWORD + + inc dword[arp_tx_count] ; increase counter + + sub esp, 28 ; allocate memory for ARP_PACKET + + mov word[esp + ARP_PACKET.HardwareType],0x0100 ;Ethernet + mov word[esp + ARP_PACKET.ProtocolType],0x0008 ;IP + mov byte[esp + ARP_PACKET.HardwareSize],0x06 ;MAC-addr length + mov byte[esp + ARP_PACKET.ProtocolSize],0x04 ;IP-addr length + mov word[esp + ARP_PACKET.Opcode],0x0100 ;Request + + cld + mov esi,[SenderMAC_ptr] + lea edi,[esp + ARP_PACKET.SenderMAC] ;Our MAC-addr + movsd + movsw + + mov esi,[SenderIP_ptr] + lea edi,[esp + ARP_PACKET.SenderIP] ;Our IP-addr + movsd + + xor eax, eax + lea edi, [esp + ARP_PACKET.TargetMAC] ;Required MAC-addr(zeroed) + stosd + stosw + + mov esi, dword[TargetIP] + mov dword[esp + ARP_PACKET.TargetIP],esi ;Required IP-addr(we get it as function parameter) + + ; Now, send it! + mov edi, broadcast_add ; Pointer to 48 bit destination address + mov bx, ETHER_ARP ; Type of packet + mov ecx, 28 ; size of packet + lea esi, [esp + ARP_PACKET]; pointer to packet data + call dword [drvr_transmit] ; Call the drivers transmit function + + add esp, 28 ; free memory, allocated before for ARP_PACKET + + ; Add an entry in the ARP table, awaiting response + sub esp, ARP_ENTRY_SIZE ;allocate memory for ARP-entry + + mov esi, dword[TargetIP] + mov dword[esp + ARP_ENTRY.IP],esi + + lea edi, [esp + ARP_ENTRY.MAC] + xor eax, eax + stosd + stosw + + mov word[esp + ARP_ENTRY.Status], ARP_AWAITING_RESPONSE + mov word[esp + ARP_ENTRY.TTL], 0x000A ; 10 seconds + + stdcall arp_table_manager,ARP_TABLE_ADD,EXTRA_IS_ARP_ENTRY_PTR,esp + add esp, ARP_ENTRY_SIZE ; free memory + +.exit: + ret +endp diff --git a/kernel/trunk/network/eth_drv/drivers/3c59x.inc b/kernel/trunk/network/eth_drv/drivers/3c59x.inc new file mode 100644 index 0000000000..4280823c59 --- /dev/null +++ b/kernel/trunk/network/eth_drv/drivers/3c59x.inc @@ -0,0 +1,2380 @@ +;; Copyright (c) 2004, Endre Kozma +;; All rights reserved. +;; +;; Redistribution and use in source and binary forms, with or without +;; modification, are permitted provided that the following conditions are +;; met: +;; +;; 1. Redistributions of source code must retain the above copyright notice, +;; this list of conditions and the following disclaimer. +;; +;; 2. Redistributions in binary form must reproduce the above copyright +;; notice, this list of conditions and the following disclaimer in the +;; documentation and/or other materials provided with the distribution. +;; +;; 3. The name of the author may not be used to endorse or promote products +;; derived from this software without specific prior written permission. +;; +;; THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR +;; IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +;; OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. +;; IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, +;; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT +;; NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +;; DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +;; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +;; (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF +;; THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; 3C59X.INC ;; +;; ;; +;; Ethernet driver for Menuet OS ;; +;; ;; +;; Driver for 3Com fast etherlink 3c59x and ;; +;; etherlink XL 3c900 and 3c905 cards ;; +;; References: ;; +;; www.3Com.com - data sheets ;; +;; DP83840A.pdf - ethernet physical layer ;; +;; 3c59x.c - linux driver ;; +;; ethernet driver template by Mike Hibbett ;; +;; ;; +;; Credits ;; +;; Mike Hibbett, ;; +;; who kindly supplied me with a 3Com905C-TX-M card ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; History +;; ======= +;; $Log: 3C59X.INC,v $ +;; Revision 1.3 2004/07/11 12:21:12 kozma +;; Support of vortex chips (3c59x) added. +;; Support of 3c920 and 3c982 added. +;; Corrections. +;; +;; Revision 1.2 2004/06/12 19:40:20 kozma +;; Function e3c59x_set_available_media added in order to set +;; the default media in case auto detection finds no valid link. +;; Incorrect mii check removed (3c900 Cyclone works now). +;; Cleanups. +;; +;; Revision 1.1 2004/06/12 18:27:15 kozma +;; Initial revision +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; comment the next line out if you don't want debug info printed +; on the debug board. This option adds a lot of bytes to the driver +; so it's worth to comment it out. +; E3C59X_DEBUG equ 1 + +; forcing full duplex mode makes sense at some cards and link types + E3C59X_FORCE_FD equ 1 + +macro virt_to_dma reg +{ +if defined E3C59X_LINUX + sub reg, [virt_addr] + add reg, [dma_addr] +end if +} + +macro dma_to_virt reg +{ +if defined E3C59X_LINUX + sub reg, [dma_addr] + add reg, [virt_addr] +end if +} + +macro zero_to_virt reg +{ +if defined E3C59X_LINUX + add reg, [virt_addr] +end if +} + +macro virt_to_zero reg +{ +if defined E3C59X_LINUX + sub reg, [virt_addr] +end if +} + +macro zero_to_dma reg +{ +if defined E3C59X_LINUX + add reg, [dma_addr] +end if +} + +macro dma_to_zero reg +{ +if defined E3C59X_LINUX + sub reg, [dma_addr] +end if +} + +macro strtbl name, [string] +{ +common + label name dword +forward + local label + dd label +forward + label db string, 0 +} + +; Ethernet frame symbols + ETH_ALEN equ 6 + ETH_HLEN equ (2*ETH_ALEN+2) + ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for + ; mininmum 64bytes frame length +; PCI programming + PCI_REG_COMMAND equ 0x4 ; command register + PCI_REG_STATUS equ 0x6 ; status register + PCI_REG_LATENCY equ 0xd ; latency timer register + PCI_REG_CAP_PTR equ 0x34 ; capabilities pointer + PCI_REG_CAPABILITY_ID equ 0x0 ; capapility ID in pm register block + PCI_REG_PM_STATUS equ 0x4 ; power management status register + PCI_REG_PM_CTRL equ 0x4 ; power management control register + PCI_BIT_PIO equ 0 ; bit0: io space control + PCI_BIT_MMIO equ 1 ; bit1: memory space control + PCI_BIT_MASTER equ 2 ; bit2: device acts as a PCI master +; Registers + E3C59X_REG_POWER_MGMT_CTRL equ 0x7c + E3C59X_REG_UP_LIST_PTR equ 0x38 + E3C59X_REG_UP_PKT_STATUS equ 0x30 + E3C59X_REG_TX_FREE_THRESH equ 0x2f + E3C59X_REG_DN_LIST_PTR equ 0x24 + E3C59X_REG_DMA_CTRL equ 0x20 + E3C59X_REG_TX_STATUS equ 0x1b + E3C59X_REG_RX_STATUS equ 0x18 + E3C59X_REG_TX_DATA equ 0x10 +; Common window registers + E3C59X_REG_INT_STATUS equ 0xe + E3C59X_REG_COMMAND equ 0xe +; Register window 7 + E3C59X_REG_MASTER_STATUS equ 0xc + E3C59X_REG_POWER_MGMT_EVENT equ 0xc + E3C59X_REG_MASTER_LEN equ 0x6 + E3C59X_REG_VLAN_ETHER_TYPE equ 0x4 + E3C59X_REG_VLAN_MASK equ 0x0 + E3C59X_REG_MASTER_ADDRESS equ 0x0 +; Register window 6 + E3C59X_REG_BYTES_XMITTED_OK equ 0xc + E3C59X_REG_BYTES_RCVD_OK equ 0xa + E3C59X_REG_UPPER_FRAMES_OK equ 0x9 + E3C59X_REG_FRAMES_DEFERRED equ 0x8 + E3C59X_REG_FRAMES_RCVD_OK equ 0x7 + E3C59X_REG_FRAMES_XMITTED_OK equ 0x6 + E3C59X_REG_RX_OVERRUNS equ 0x5 + E3C59X_REG_LATE_COLLISIONS equ 0x4 + E3C59X_REG_SINGLE_COLLISIONS equ 0x3 + E3C59X_REG_MULTIPLE_COLLISIONS equ 0x2 + E3C59X_REG_SQE_ERRORS equ 0x1 + E3C59X_REG_CARRIER_LOST equ 0x0 +; Register window 5 + E3C59X_REG_INDICATION_ENABLE equ 0xc + E3C59X_REG_INTERRUPT_ENABLE equ 0xa + E3C59X_REG_TX_RECLAIM_THRESH equ 0x9 + E3C59X_REG_RX_FILTER equ 0x8 + E3C59X_REG_RX_EARLY_THRESH equ 0x6 + E3C59X_REG_TX_START_THRESH equ 0x0 +; Register window 4 + E3C59X_REG_UPPER_BYTES_OK equ 0xe + E3C59X_REG_BAD_SSD equ 0xc + E3C59X_REG_MEDIA_STATUS equ 0xa + E3C59X_REG_PHYSICAL_MGMT equ 0x8 + E3C59X_REG_NETWORK_DIAGNOSTIC equ 0x6 + E3C59X_REG_FIFO_DIAGNOSTIC equ 0x4 + E3C59X_REG_VCO_DIAGNOSTIC equ 0x2 ; may not supported +; Bits in register window 4 + E3C59X_BIT_AUTOSELECT equ 24 +; Register window 3 + E3C59X_REG_TX_FREE equ 0xc + E3C59X_REG_RX_FREE equ 0xa + E3C59X_REG_MEDIA_OPTIONS equ 0x8 + E3C59X_REG_MAC_CONTROL equ 0x6 + E3C59X_REG_MAX_PKT_SIZE equ 0x4 + E3C59X_REG_INTERNAL_CONFIG equ 0x0 +; Register window 2 + E3C59X_REG_RESET_OPTIONS equ 0xc + E3C59X_REG_STATION_MASK_HI equ 0xa + E3C59X_REG_STATION_MASK_MID equ 0x8 + E3C59X_REG_STATION_MASK_LO equ 0x6 + E3C59X_REG_STATION_ADDRESS_HI equ 0x4 + E3C59X_REG_STATION_ADDRESS_MID equ 0x2 + E3C59X_REG_STATION_ADDRESS_LO equ 0x0 +; Register window 1 + E3C59X_REG_TRIGGER_BITS equ 0xc + E3C59X_REG_SOS_BITS equ 0xa + E3C59X_REG_WAKE_ON_TIMER equ 0x8 + E3C59X_REG_SMB_RXBYTES equ 0x7 + E3C59X_REG_SMB_DIAG equ 0x5 + E3C59X_REG_SMB_ARB equ 0x4 + E3C59X_REG_SMB_STATUS equ 0x2 + E3C59X_REG_SMB_ADDRESS equ 0x1 + E3C59X_REG_SMB_FIFO_DATA equ 0x0 +; Register window 0 + E3C59X_REG_EEPROM_DATA equ 0xc + E3C59X_REG_EEPROM_COMMAND equ 0xa + E3C59X_REG_BIOS_ROM_DATA equ 0x8 + E3C59X_REG_BIOS_ROM_ADDR equ 0x4 +; Physical management bits + E3C59X_BIT_MGMT_DIR equ 2 ; drive with the data written in mgmtData + E3C59X_BIT_MGMT_DATA equ 1 ; MII management data bit + E3C59X_BIT_MGMT_CLK equ 0 ; MII management clock +; MII commands + E3C59X_MII_CMD_MASK equ (1111b shl 10) + E3C59X_MII_CMD_READ equ (0110b shl 10) + E3C59X_MII_CMD_WRITE equ (0101b shl 10) +; MII registers + E3C59X_REG_MII_BMCR equ 0 ; basic mode control register + E3C59X_REG_MII_BMSR equ 1 ; basic mode status register + E3C59X_REG_MII_ANAR equ 4 ; auto negotiation advertisement register + E3C59X_REG_MII_ANLPAR equ 5 ; auto negotiation link partner ability register + E3C59X_REG_MII_ANER equ 6 ; auto negotiation expansion register +; MII bits + E3C59X_BIT_MII_AUTONEG_COMPLETE equ 5 ; auto-negotiation complete + E3C59X_BIT_MII_PREAMBLE_SUPPRESSION equ 6 +; eeprom bits and commands + E3C59X_EEPROM_CMD_READ equ 0x80 + E3C59X_EEPROM_BIT_BUSY equ 15 +; eeprom registers + E3C59X_EEPROM_REG_OEM_NODE_ADDR equ 0xa + E3C59X_EEPROM_REG_CAPABILITIES equ 0x10 +; Commands for command register + E3C59X_SELECT_REGISTER_WINDOW equ (1 shl 11) + + IS_VORTEX equ 0x1 + IS_BOOMERANG equ 0x2 + IS_CYCLONE equ 0x4 + IS_TORNADO equ 0x8 + EEPROM_8BIT equ 0x10 + HAS_PWR_CTRL equ 0x20 + HAS_MII equ 0x40 + HAS_NWAY equ 0x80 + HAS_CB_FNS equ 0x100 + INVERT_MII_PWR equ 0x200 + INVERT_LED_PWR equ 0x400 + MAX_COLLISION_RESET equ 0x800 + EEPROM_OFFSET equ 0x1000 + HAS_HWCKSM equ 0x2000 + EXTRA_PREAMBLE equ 0x4000 + +iglobal + align 4 +e3c59x_hw_versions: + dw 0x5900, IS_VORTEX ; 3c590 Vortex 10Mbps + dw 0x5920, IS_VORTEX ; 3c592 EISA 10Mbps Demon/Vortex + dw 0x5970, IS_VORTEX ; 3c597 EISA Fast Demon/Vortex + dw 0x5950, IS_VORTEX ; 3c595 Vortex 100baseTx + dw 0x5951, IS_VORTEX ; 3c595 Vortex 100baseT4 + dw 0x5952, IS_VORTEX ; 3c595 Vortex 100base-MII + dw 0x9000, IS_BOOMERANG ; 3c900 Boomerang 10baseT + dw 0x9001, IS_BOOMERANG ; 3c900 Boomerang 10Mbps Combo + dw 0x9004, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c900 Cyclone 10Mbps TPO + dw 0x9005, IS_CYCLONE or HAS_HWCKSM ; 3c900 Cyclone 10Mbps Combo + dw 0x9006, IS_CYCLONE or HAS_HWCKSM ; 3c900 Cyclone 10Mbps TPC + dw 0x900A, IS_CYCLONE or HAS_HWCKSM ; 3c900B-FL Cyclone 10base-FL + dw 0x9050, IS_BOOMERANG or HAS_MII ; 3c905 Boomerang 100baseTx + dw 0x9051, IS_BOOMERANG or HAS_MII ; 3c905 Boomerang 100baseT4 + dw 0x9055, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM or EXTRA_PREAMBLE ; 3c905B Cyclone 100baseTx + dw 0x9058, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c905B Cyclone 10/100/BNC + dw 0x905A, IS_CYCLONE or HAS_HWCKSM ; 3c905B-FX Cyclone 100baseFx + dw 0x9200, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c905C Tornado + dw 0x9800, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3c980 Cyclone + dw 0x9805, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c982 Dual Port Server Cyclone + dw 0x7646, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM ; 3cSOHO100-TX Hurricane + dw 0x5055, IS_CYCLONE or EEPROM_8BIT or HAS_HWCKSM ; 3c555 Laptop Hurricane + dw 0x6055, IS_TORNADO or HAS_NWAY or EEPROM_8BIT or HAS_CB_FNS \ + or INVERT_MII_PWR or HAS_HWCKSM ; 3c556 Laptop Tornado + dw 0x6056, IS_TORNADO or HAS_NWAY or EEPROM_OFFSET or HAS_CB_FNS \ + or INVERT_MII_PWR or HAS_HWCKSM ; 3c556B Laptop Hurricane + dw 0x5b57, IS_BOOMERANG or HAS_MII or EEPROM_8BIT ; 3c575 [Megahertz] 10/100 LAN CardBus + dw 0x5057, IS_BOOMERANG or HAS_MII or EEPROM_8BIT ; 3c575 Boomerang CardBus + dw 0x5157, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT \ + or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFE575BT Cyclone CardBus + dw 0x5257, IS_TORNADO or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR \ + or MAX_COLLISION_RESET or HAS_HWCKSM ; 3CCFE575CT Tornado CardBus + dw 0x6560, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR \ + or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFE656 Cyclone CardBus + dw 0x6562, IS_CYCLONE or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR \ + or INVERT_LED_PWR or HAS_HWCKSM ; 3CCFEM656B Cyclone+Winmodem CardBus + dw 0x6564, IS_TORNADO or HAS_NWAY or HAS_CB_FNS or EEPROM_8BIT or INVERT_MII_PWR \ + or MAX_COLLISION_RESET or HAS_HWCKSM ; 3CXFEM656C Tornado+Winmodem CardBus + dw 0x4500, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c450 HomePNA Tornado + dw 0x9201, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c920 Tornado + dw 0x1201, IS_TORNADO or HAS_HWCKSM or HAS_NWAY ; 3c982 Hydra Dual Port A + dw 0x1202, IS_TORNADO or HAS_HWCKSM or HAS_NWAY ; 3c982 Hydra Dual Port B + dw 0x9056, IS_CYCLONE or HAS_NWAY or HAS_HWCKSM or EXTRA_PREAMBLE ; 3c905B-T4 + dw 0x9210, IS_TORNADO or HAS_NWAY or HAS_HWCKSM ; 3c920B-EMB-WNM Tornado +E3C59X_HW_VERSIONS_SIZE= $-e3c59x_hw_versions +endg + +; RX/TX buffers sizes + E3C59X_MAX_ETH_PKT_SIZE equ 1536 ; max packet size + E3C59X_NUM_RX_DESC equ 4 ; a power of 2 number + E3C59X_NUM_TX_DESC equ 4 ; a power of 2 number + E3C59X_RX_BUFFER_SIZE equ (E3C59X_MAX_ETH_FRAME_SIZE*E3C59X_NUM_RX_DESC) + E3C59X_TX_BUFFER_SIZE equ (E3C59X_MAX_ETH_FRAME_SIZE*E3C59X_NUM_TX_DESC) +; Download Packet Descriptor + E3C59X_DPD_DN_NEXT_PTR equ 0 + E3C59X_DPD_FRAME_START_HDR equ 4 + E3C59X_DPD_DN_FRAG_ADDR equ 8 ; for packet data + E3C59X_DPD_DN_FRAG_LEN equ 12 ; for packet data + E3C59X_DPD_SIZE equ 16 ; a power of 2 number +; Upload Packet Descriptor + E3C59X_UPD_UP_NEXT_PTR equ 0 + E3C59X_UPD_PKT_STATUS equ 4 + E3C59X_UPD_UP_FRAG_ADDR equ 8 ; for packet data + E3C59X_UPD_UP_FRAG_LEN equ 12 ; for packet data + E3C59X_UPD_SIZE equ 16 + +; RX/TX buffers +if defined E3C59X_LINUX + E3C59X_MAX_ETH_FRAME_SIZE = 160 ; size of ethernet frame + bytes alignment + e3c59x_rx_buff = 0 +else + E3C59X_MAX_ETH_FRAME_SIZE = 1520 ; size of ethernet frame + bytes alignment + e3c59x_rx_buff = eth_data_start +end if + + e3c59x_tx_buff = e3c59x_rx_buff+E3C59X_RX_BUFFER_SIZE + e3c59x_dpd_buff = e3c59x_tx_buff+E3C59X_TX_BUFFER_SIZE + e3c59x_upd_buff = e3c59x_dpd_buff+(E3C59X_DPD_SIZE*E3C59X_NUM_TX_DESC) + +uglobal +e3c59x_curr_upd: dd 0 +e3c59x_prev_dpd: dd 0 +e3c59x_prev_tx_frame: dd 0 +e3c59x_transmit_function: dd 0 +e3c59x_receive_function: dd 0 +endg + +iglobal +e3c59x_ver_id: db 17 +endg +uglobal +e3c59x_full_bus_master: db 0 +e3c59x_has_hwcksm: db 0 +e3c59x_preamble: db 0 +e3c59x_dn_list_ptr_cleared: db 0 +e3c59x_self_directed_packet: rb 6 +endg + +if defined E3C59X_DEBUG +e3c59x_hw_type_str: db "Detected hardware type : ", 0 +e3c59x_device_str: db "Device ID : 0x" +e3c59x_device_id_str: db "ffff", 13, 10, 0 +e3c59x_vendor_str: db "Vendor ID : 0x" +e3c59x_vendor_id_str: db "ffff", 13, 10, 0 +e3c59x_io_info_str: db "IO address : 0x" +e3c59x_io_addr_str: db "ffff", 13, 10, 0 +e3c59x_mac_info_str: db "MAC address : " +e3c59x_mac_addr_str: db "ff:ff:ff:ff:ff:ff", 13, 10, 0 +e3c59x_boomerang_str: db " (boomerang)", 13, 10, 0 +e3c59x_vortex_str: db " (vortex)", 13, 10, 0 +e3c59x_link_type_str: db "Established link type : ", 0 +e3c59x_new_line_str: db 13, 10, 0 +e3c59x_link_type: dd 0 + +e3c59x_charset: db '0123456789abcdef' + +strtbl e3c59x_link_str, \ + "No valid link type detected", \ + "10BASE-T half duplex", \ + "10BASE-T full-duplex", \ + "100BASE-TX half duplex", \ + "100BASE-TX full duplex", \ + "100BASE-T4", \ + "100BASE-FX", \ + "10Mbps AUI", \ + "10Mbps COAX (BNC)", \ + "miiDevice - not supported" + +strtbl e3c59x_hw_str, \ + "3c590 Vortex 10Mbps", \ + "3c592 EISA 10Mbps Demon/Vortex", \ + "3c597 EISA Fast Demon/Vortex", \ + "3c595 Vortex 100baseTx", \ + "3c595 Vortex 100baseT4", \ + "3c595 Vortex 100base-MII", \ + "3c900 Boomerang 10baseT", \ + "3c900 Boomerang 10Mbps Combo", \ + "3c900 Cyclone 10Mbps TPO", \ + "3c900 Cyclone 10Mbps Combo", \ + "3c900 Cyclone 10Mbps TPC", \ + "3c900B-FL Cyclone 10base-FL", \ + "3c905 Boomerang 100baseTx", \ + "3c905 Boomerang 100baseT4", \ + "3c905B Cyclone 100baseTx", \ + "3c905B Cyclone 10/100/BNC", \ + "3c905B-FX Cyclone 100baseFx", \ + "3c905C Tornado", \ + "3c980 Cyclone", \ + "3c982 Dual Port Server Cyclone", \ + "3cSOHO100-TX Hurricane", \ + "3c555 Laptop Hurricane", \ + "3c556 Laptop Tornado", \ + "3c556B Laptop Hurricane", \ + "3c575 [Megahertz] 10/100 LAN CardBus", \ + "3c575 Boomerang CardBus", \ + "3CCFE575BT Cyclone CardBus", \ + "3CCFE575CT Tornado CardBus", \ + "3CCFE656 Cyclone CardBus", \ + "3CCFEM656B Cyclone+Winmodem CardBus", \ + "3CXFEM656C Tornado+Winmodem CardBus", \ + "3c450 HomePNA Tornado", \ + "3c920 Tornado", \ + "3c982 Hydra Dual Port A", \ + "3c982 Hydra Dual Port B", \ + "3c905B-T4", \ + "3c920B-EMB-WNM Tornado" + +end if ; defined E3C59X_DEBUG + +;*************************************************************************** +; Function +; e3c59x_debug +; Description +; prints debug info to the debug board +; Parameters +; ebp - io_addr +; Return value +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;*************************************************************************** +if defined E3C59X_DEBUG + align 4 +e3c59x_debug: + pushad +; print device type + mov esi, e3c59x_hw_type_str + call sys_msg_board_str + movzx ecx, byte [e3c59x_ver_id] + mov esi, [e3c59x_hw_str+ecx*4] + call sys_msg_board_str + mov esi, e3c59x_boomerang_str + cmp dword [e3c59x_transmit_function], e3c59x_boomerang_transmit + jz .boomerang + mov esi, e3c59x_vortex_str +.boomerang: + call sys_msg_board_str +; print device/vendor + mov ax, [pci_data+2] + mov cl, 2 + mov ebx, e3c59x_device_id_str + call e3c59x_print_hex + mov esi, e3c59x_device_str + call sys_msg_board_str + mov ax, [pci_data] + mov cl, 2 + mov ebx, e3c59x_vendor_id_str + call e3c59x_print_hex + mov esi, e3c59x_vendor_str + call sys_msg_board_str +; print io address + mov ax, [io_addr] + mov ebx, e3c59x_io_addr_str + mov cl, 2 + call e3c59x_print_hex + mov esi, e3c59x_io_info_str + call sys_msg_board_str +; print MAC address + mov ebx, e3c59x_mac_addr_str + xor ecx, ecx +.mac_loop: + push ecx + mov al, [node_addr+ecx] + mov cl, 1 + call e3c59x_print_hex + inc ebx + pop ecx + inc cl + cmp cl, 6 + jne .mac_loop + mov esi, e3c59x_mac_info_str + call sys_msg_board_str +; print link type + mov esi, e3c59x_link_type_str + call sys_msg_board_str + xor eax, eax + bsr ax, word [e3c59x_link_type] + jz @f + sub ax, 4 +@@: + mov esi, [e3c59x_link_str+eax*4] + call sys_msg_board_str + mov esi, e3c59x_new_line_str + call sys_msg_board_str + popad + ret + +;*************************************************************************** +; Function +; e3c59x_print_hex +; Description +; prints a hexadecimal value +; Parameters +; eax - value to be printed out +; ebx - where to print +; cl - value size (1, 2, 4) +; Return value +; ebx - end address after the print +; Destroyed registers +; eax, ebx +; +;*************************************************************************** + align 4 +e3c59x_print_hex: + cmp cl, 1 + je .print_byte + cmp cl, 2 + jz .print_word +.print_dword: + push eax + bswap eax + xchg ah, al + call .print_word + pop eax +.print_word: + push eax + xchg ah, al + call .print_byte + pop eax +.print_byte: + movzx eax, al + push eax + and al, 0xf0 + shr al, 4 + mov al, byte [eax+e3c59x_charset] + mov [ebx], al + inc ebx + pop eax + and al, 0x0f + mov al, byte [eax+e3c59x_charset] + mov [ebx], al + inc ebx + ret +end if ; defined E3C59X_DEBUG + +;*************************************************************************** +; Function +; e3c59x_try_link_detect +; Description +; e3c59x_try_link_detect checks if link exists +; Parameters +; ebp - io_addr +; Return value +; al - 0 ; no link detected +; al - 1 ; link detected +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;*************************************************************************** + align 4 +e3c59x_try_link_detect: +; download self-directed packet + mov edi, node_addr + mov bx, 0x0608 ; packet type + mov esi, e3c59x_self_directed_packet + mov ecx, 6 ; 6 + 6 + 2 + 6 = 20 bytes + call dword [e3c59x_transmit_function] +; switch to register window 5 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+5 + out dx, ax +; program RxFilter for promiscuous operation + mov ax, (10000b shl 11) + lea edx, [ebp+E3C59X_REG_RX_FILTER] + in al, dx + or al, 1111b + lea edx, [ebp+E3C59X_REG_COMMAND] + out dx, ax +; switch to register window 4 + mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 + out dx, ax +; check loop + xor ebx, ebx + mov ecx, 0xffff ; 65535 tries +.loop: + push ecx ebx + call dword [e3c59x_receive_function] + pop ebx ecx + test al, al + jnz .finish +.no_packet_received: +; switch to register window 4 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 + out dx, ax +; read linkbeatdetect + lea edx, [ebp+E3C59X_REG_MEDIA_STATUS] + in ax, dx + test ah, 1000b ; test linkBeatDetect + jnz .link_detected + xor al, al + jmp .finish +.link_detected: +; test carrierSense + test al, 100000b + jz .no_carrier_sense + inc ebx +.no_carrier_sense: + dec ecx + jns .loop +; assume the link is good if 0 < ebx < 25 % + test ebx, ebx + setnz al + jz .finish + cmp ebx, 16384 ; 25% + setb al +.finish: +if defined E3C59X_DEBUG + test al, al + jz @f + or byte [e3c59x_link_type+1], 100b +@@: +end if ; defined E3C59X_DEBUG + ret + +;*************************************************************************** +; Function +; e3c59x_try_phy +; Description +; e3c59x_try_phy checks the auto-negotiation function +; in the PHY at PHY index. It can also be extended to +; include link detection for non-IEEE 802.3u +; auto-negotiation devices, for instance the BCM5000. +; Parameters +; ah - PHY index +; ebp - io_addr +; Return value +; al - 0 link is auto-negotiated +; al - 1 no link is auto-negotiated +; Destroyed registers +; eax, ebx, ecx, edx, esi +; +;*************************************************************************** + align 4 +e3c59x_try_phy: + mov al, E3C59X_REG_MII_BMCR + push eax + call e3c59x_mdio_read ; returns with window #4 + or ah, 0x80 ; software reset + mov ebx, eax + pop eax + push eax + call e3c59x_mdio_write ; returns with window #4 +; wait for reset to complete + mov esi, 2000 ; 2000ms = 2s + call delay_ms + pop eax + push eax + call e3c59x_mdio_read ; returns with window #4 + test ah, 0x80 + jnz .fail_finish + pop eax + push eax +; wait for a while after reset + mov esi, 20 ; 20ms + call delay_ms + pop eax + push eax + mov al, E3C59X_REG_MII_BMSR + call e3c59x_mdio_read ; returns with window #4 + test al, 1 ; extended capability supported? + jz .no_ext_cap +; auto-neg capable? + test al, 1000b + jz .fail_finish ; not auto-negotiation capable +; auto-neg complete? + test al, 100000b + jnz .auto_neg_ok +; restart auto-negotiation + pop eax + push eax + mov al, E3C59X_REG_MII_ANAR + push eax + call e3c59x_mdio_read ; returns with window #4 + or ax, (1111b shl 5) ; advertise only 10base-T and 100base-TX + mov ebx, eax + pop eax + call e3c59x_mdio_write ; returns with window #4 + pop eax + push eax + call e3c59x_mdio_read ; returns with window #4 + mov ebx, eax + or bh, 10010b ; restart auto-negotiation + pop eax + push eax + call e3c59x_mdio_write ; returns with window #4 + mov esi, 4000 ; 4000ms = 4 seconds + call delay_ms + pop eax + push eax + mov al, E3C59X_REG_MII_BMSR + call e3c59x_mdio_read ; returns with window #4 + test al, 100000b ; auto-neg complete? + jnz .auto_neg_ok + jmp .fail_finish +.auto_neg_ok: +; compare advertisement and link partner ability registers + pop eax + push eax + mov al, E3C59X_REG_MII_ANAR + call e3c59x_mdio_read ; returns with window #4 + xchg eax, [esp] + mov al, E3C59X_REG_MII_ANLPAR + call e3c59x_mdio_read ; returns with window #4 + pop ebx + and eax, ebx + and eax, 1111100000b + push eax +if defined E3C59X_DEBUG + mov word [e3c59x_link_type], ax +end if ; defined E3C59X_DEBUG +; switch to register window 3 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 + out dx, ax +; set full-duplex mode + lea edx, [ebp+E3C59X_REG_MAC_CONTROL] + in ax, dx + and ax, not 0x120 ; clear full duplex and flow control + pop ebx + test ebx, (1010b shl 5) ; check for full-duplex + jz .half_duplex + or ax, 0x120 ; set full duplex and flow control +.half_duplex: + out dx, ax + mov al, 1 + ret +.no_ext_cap: +; not yet implemented BCM5000 +.fail_finish: + pop eax + xor al, al + ret + +;*************************************************************************** +; Function +; e3c59x_try_mii +; Description +; e3c59x_try_MII checks the on-chip auto-negotiation logic +; or an off-chip MII PHY, depending upon what is set in +; xcvrSelect by the caller. +; It exits when it finds the first device with a good link. +; Parameters +; ebp - io_addr +; Return value +; al - 0 +; al - 1 +; Destroyed registers +; eax, ebx, ecx, edx, esi +; +;*************************************************************************** + align 4 +e3c59x_try_mii: +; switch to register window 3 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 + out dx, ax + lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] + in eax, dx + and eax, (1111b shl 20) + cmp eax, (1000b shl 20) ; is auto-negotiation set? + jne .mii_device +; auto-negotiation is set +; switch to register window 4 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 + out dx, ax +; PHY==24 is the on-chip auto-negotiation logic +; it supports only 10base-T and 100base-TX + mov ah, 24 + call e3c59x_try_phy + test al, al + jz .fail_finish + mov cl, 24 + jmp .check_preamble +.mii_device: + cmp eax, (0110b shl 20) + jne .fail_finish + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 + out dx, ax + lea edx, [ebp+E3C59X_REG_PHYSICAL_MGMT] + in ax, dx + and al, (1 shl E3C59X_BIT_MGMT_DIR) or (1 shl E3C59X_BIT_MGMT_DATA) + cmp al, (1 shl E3C59X_BIT_MGMT_DATA) + je .serch_for_phy + xor al, al + ret +.serch_for_phy: +; search for PHY + mov cl, 31 +.search_phy_loop: + cmp cl, 24 + je .next_phy + mov ah, cl ; ah = phy + mov al, E3C59X_REG_MII_BMCR ; al = Basic Mode Status Register + push ecx + call e3c59x_mdio_read + pop ecx + test ax, ax + jz .next_phy + cmp ax, 0xffff + je .next_phy + mov ah, cl ; ah = phy + push ecx + call e3c59x_try_phy + pop ecx + test al, al + jnz .check_preamble +.next_phy: + dec cl + jns .search_phy_loop +.fail_finish: + xor al, al + ret +; epilog +.check_preamble: + push eax ; eax contains the return value of e3c59x_try_phy +; check hard coded preamble forcing + movzx eax, byte [e3c59x_ver_id] + test word [eax*4+e3c59x_hw_versions+2], EXTRA_PREAMBLE + setnz [e3c59x_preamble] ; force preamble + jnz .finish +; check mii for preamble suppression + mov ah, cl + mov al, E3C59X_REG_MII_BMSR + call e3c59x_mdio_read + test al, 1000000b ; preamble suppression? + setz [e3c59x_preamble] ; no +.finish: + pop eax + ret + +;*************************************************************************** +; Function +; e3c59x_test_packet +; Description +; e3c59x_try_loopback try a loopback packet for 10BASE2 or AUI port +; Parameters +; ebp - io_addr +; Return value +; al - 0 +; al - 1 +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;*************************************************************************** + align 4 +e3c59x_test_packet: +; switch to register window 3 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 + out dx, ax +; set fullDuplexEnable in MacControl register + lea edx, [ebp+E3C59X_REG_MAC_CONTROL] + in ax, dx + or ax, 0x120 + out dx, ax +; switch to register window 5 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+5 + out dx, ax +; set RxFilter to enable individual address matches + mov ax, (10000b shl 11) + lea edx, [ebp+E3C59X_REG_RX_FILTER] + in al, dx + or al, 1 + lea edx, [ebp+E3C59X_REG_COMMAND] + out dx, ax +; issue RxEnable and TxEnable + call e3c59x_rx_reset + call e3c59x_tx_reset +; download a self-directed test packet + mov edi, node_addr + mov bx, 0x0608 ; packet type + mov esi, e3c59x_self_directed_packet + mov ecx, 6 ; 6 + 6 + 2 + 6 = 20 bytes + call dword [e3c59x_transmit_function] +; wait for 2s + mov esi, 2000 ; 2000ms = 2s + call delay_ms +; check if self-directed packet is received + call dword [e3c59x_receive_function] + test al, al + jnz .finish +; switch to register window 3 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 + out dx, ax +; clear fullDuplexEnable in MacControl register + lea edx, [ebp+E3C59X_REG_MAC_CONTROL] + in ax, dx + and ax, not 0x120 + out dx, ax + xor al, al +.finish: + ret + +;*************************************************************************** +; Function +; e3c59x_try_loopback +; Description +; tries a loopback packet for 10BASE2 or AUI port +; Parameters +; al - 0: 10Mbps AUI connector +; 1: 10BASE-2 +; ebp - io_addr +; Return value +; al - 0 +; al - 1 +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;*************************************************************************** + align 4 +e3c59x_try_loopback: + push eax +; switch to register window 3 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 + out dx, ax + pop eax + push eax +if defined E3C59X_DEBUG + mov bl, al + inc bl + shl bl, 3 + or byte [e3c59x_link_type+1], bl +end if ; defined E3C59X_DEBUG + test al, al ; aui or coax? + jz .complete_loopback +; enable 100BASE-2 DC-DC converter + mov ax, (10b shl 11) ; EnableDcConverter + out dx, ax +.complete_loopback: + mov cl, 2 ; give a port 3 chances to complete a loopback +.next_try: + push ecx + call e3c59x_test_packet + pop ecx + test al, al + jnz .finish + dec cl + jns .next_try +.finish: + xchg eax, [esp] + test al, al + jz .aui_finish +; issue DisableDcConverter command + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, (10111b shl 11) + out dx, ax +.aui_finish: + pop eax ; al contains the result of operation +if defined E3C59X_DEBUG + test al, al + jnz @f + and byte [e3c59x_link_type+1], not 11000b +@@: +end if ; defined E3C59X_DEBUG + ret + +;*************************************************************************** +; Function +; e3c59x_set_available_media +; Description +; sets the first available media +; Parameters +; ebp - io_addr +; Return value +; al - 0 +; al - 1 +; Destroyed registers +; eax, edx +; +;*************************************************************************** + align 4 +e3c59x_set_available_media: +; switch to register window 3 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 + out dx, ax + lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] + in eax, dx + push eax + lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS] + in ax, dx + test al, 10b + jz @f +; baseTXAvailable + pop eax + and eax, not (1111b shl 20) + or eax, (100b shl 20) +if defined E3C59X_DEBUG & defined E3C59X_FORCE_FD + mov word [e3c59x_link_type], (1 shl 8) +else if defined E3C59X_DEBUG + mov word [e3c59x_link_type], (1 shl 7) +end if + jmp .set_media +@@: + test al, 100b + jz @f +; baseFXAvailable + pop eax + and eax, not (1111b shl 20) + or eax, (101b shl 20) +if defined E3C59X_DEBUG + mov word [e3c59x_link_type], (1 shl 10) +end if + jmp .set_media +@@: + test al, 1000000b + jz @f +; miiDevice + pop eax + and eax, not (1111b shl 20) + or eax, (0110b shl 20) +if defined E3C59X_DEBUG + mov word [e3c59x_link_type], (1 shl 13) +end if + jmp .set_media +@@: + test al, 1000b + jz @f +.set_default: +; 10bTAvailable + pop eax + and eax, not (1111b shl 20) +if defined E3C59X_DEBUG & defined E3C59X_FORCE_FD + mov word [e3c59x_link_type], (1 shl 6) +else if defined E3C59X_DEBUG + mov word [e3c59x_link_type], (1 shl 5) +end if ; E3C59X_FORCE_FD + jmp .set_media +@@: + test al, 10000b + jz @f +; coaxAvailable + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, (10b shl 11) ; EnableDcConverter + out dx, ax + pop eax + and eax, not (1111b shl 20) + or eax, (11b shl 20) +if defined E3C59X_DEBUG + mov word [e3c59x_link_type], (1 shl 12) +end if ; defined E3C59X_DEBUG + jmp .set_media +@@: + test al, 10000b + jz .set_default +; auiAvailable + pop eax + and eax, not (1111b shl 20) + or eax, (1 shl 20) +if defined E3C59X_DEBUG + mov word [e3c59x_link_type], (1 shl 11) +end if ; defined E3C59X_DEBUG +.set_media: + lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] + out dx, eax +if defined E3C59X_FORCE_FD +; set fullDuplexEnable in MacControl register + lea edx, [ebp+E3C59X_REG_MAC_CONTROL] + in ax, dx + or ax, 0x120 + out dx, ax +end if ; E3C59X_FORCE_FD + mov al, 1 + ret + +;*************************************************************************** +; Function +; e3c59x_set_active_port +; Description +; It selects the media port (transceiver) to be used +; Parameters: +; ebp - io_addr +; Return value: +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;*************************************************************************** + align 4 +e3c59x_set_active_port: +; switch to register window 3 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 + out dx, ax + lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] + in eax, dx + test eax, (1 shl 24) ; check if autoselect enable + jz .set_first_available_media +; check 100BASE-TX and 10BASE-T + lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS] + in ax, dx + test al, 1010b ; check whether 100BASE-TX or 10BASE-T available + jz .mii_device ; they are not available +; set auto-negotiation + lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] + in eax, dx + and eax, not (1111b shl 20) + or eax, (1000b shl 20) + out dx, eax + call e3c59x_try_mii + test al, al + jz .mii_device + ret +.mii_device: +; switch to register window 3 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 + out dx, ax +; check for off-chip mii device + lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS] + in ax, dx + test al, 1000000b ; check miiDevice + jz .base_fx + lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] + in eax, dx + and eax, not (1111b shl 20) + or eax, (0110b shl 20) ; set MIIDevice + out dx, eax + call e3c59x_try_mii + test al, al + jz .base_fx + ret +.base_fx: +; switch to register window 3 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 + out dx, ax +; check for 100BASE-FX + lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS] + in ax, dx ; read media option register + test al, 100b ; check 100BASE-FX + jz .aui_enable + lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] + in eax, dx + and eax, not (1111b shl 20) + or eax, (0101b shl 20) ; set 100base-FX + out dx, eax + call e3c59x_try_link_detect + test al, al + jz .aui_enable + ret +.aui_enable: +; switch to register window 3 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 + out dx, ax +; check for 10Mbps AUI connector + lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS] + in ax, dx ; read media option register + test al, 100000b ; check 10Mbps AUI connector + jz .coax_available + lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] + in eax, dx + and eax, not (1111b shl 20) + or eax, (0001b shl 20) ; set 10Mbps AUI connector + out dx, eax + xor al, al ; try 10Mbps AUI connector + call e3c59x_try_loopback + test al, al + jz .coax_available + ret +.coax_available: +; switch to register window 3 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+3 + out dx, ax +; check for coaxial 10BASE-2 port + lea edx, [ebp+E3C59X_REG_MEDIA_OPTIONS] + in ax, dx ; read media option register + test al, 10000b ; check 10BASE-2 + jz .set_first_available_media + lea edx, [ebp+E3C59X_REG_INTERNAL_CONFIG] + in eax, dx + and eax, not (1111b shl 20) + or eax, (0011b shl 20) ; set 10BASE-2 + out dx, eax + mov al, 1 + call e3c59x_try_loopback + test al, al + jz .set_first_available_media + ret +.set_first_available_media: + jmp e3c59x_set_available_media + +;*************************************************************************** +; Function +; e3c59x_wake_up +; Description +; set the power state to D0 +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;*************************************************************************** + align 4 +e3c59x_wake_up: +; wake up - we directly do it by programming PCI +; check if the device is power management capable + mov al, 2 + mov ah, [pci_bus] + mov bl, PCI_REG_STATUS + mov bh, [pci_dev] + push eax ebx + call pci_read_reg + test al, 10000b ; is there "new capabilities" linked list? + pop ebx eax + jz .device_awake +; search for power management register + mov al, 1 + mov bl, PCI_REG_CAP_PTR + push eax ebx + call pci_read_reg + mov cl, al + cmp cl, 0x3f + pop ebx eax + jbe .device_awake +; traverse the list + mov al, 2 +.pm_loop: + mov bl, cl + push eax ebx + call pci_read_reg + cmp al, 1 + je .set_pm_state + test ah, ah + mov cl, ah + pop ebx eax + jnz .pm_loop + jmp .device_awake +; waku up the device if necessary +.set_pm_state: + pop ebx eax + add bl, PCI_REG_PM_CTRL + push eax ebx + call pci_read_reg + mov cx, ax + test cl, 3 + pop ebx eax + jz .device_awake + and cl, not 11b ; set state to D0 + call pci_write_reg +.device_awake: + ret + +;*************************************************************************** +; Function +; e3c59x_probe +; Description +; Searches for an ethernet card, enables it and clears the rx buffer +; If a card was found, it enables the ethernet -> TCPIP link +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;*************************************************************************** + align 4 +e3c59x_probe: + movzx ebp, word [io_addr] + mov al, 2 + mov ah, [pci_bus] + mov bh, [pci_dev] + mov bl, PCI_REG_COMMAND + push ebp eax ebx + call pci_read_reg + mov cx, ax + or cl, (1 shl PCI_BIT_MASTER) or (1 shl PCI_BIT_PIO) + and cl, not (1 shl PCI_BIT_MMIO) + pop ebx eax + call pci_write_reg +; wake up the card + call e3c59x_wake_up + pop ebp +; get chip version + mov ax, [pci_data+2] + mov ecx, E3C59X_HW_VERSIONS_SIZE/4-1 +.chip_ver_loop: + cmp ax, [e3c59x_hw_versions+ecx*4] + jz .chip_ver_found + dec ecx + jns .chip_ver_loop + xor ecx, ecx +.chip_ver_found: + mov [e3c59x_ver_id], cl + test word [e3c59x_hw_versions+2+ecx*4], HAS_HWCKSM + setnz [e3c59x_has_hwcksm] +; set pci latency for vortex cards + test word [e3c59x_hw_versions+2+ecx*4], IS_VORTEX + jz .not_vortex + mov cx, 11111000b ; 248 = max latency + mov al, 1 + mov ah, [pci_bus] + mov bl, PCI_REG_LATENCY + mov bh, [pci_dev] + call pci_write_reg +.not_vortex: +; set RX/TX functions + mov ax, E3C59X_EEPROM_REG_CAPABILITIES + call e3c59x_read_eeprom + test al, 100000b ; full bus master? + setnz [e3c59x_full_bus_master] + jnz .boomerang_func + mov dword [e3c59x_transmit_function], e3c59x_vortex_transmit + mov dword [e3c59x_receive_function], e3c59x_vortex_poll + jmp @f +.boomerang_func: ; full bus master, so use boomerang functions + mov dword [e3c59x_transmit_function], e3c59x_boomerang_transmit + mov dword [e3c59x_receive_function], e3c59x_boomerang_poll +@@: +; read MAC from eeprom + mov ecx, 2 +.mac_loop: + lea ax, [E3C59X_EEPROM_REG_OEM_NODE_ADDR+ecx] + call e3c59x_read_eeprom + xchg ah, al ; htons + mov [node_addr+ecx*2], ax + dec ecx + jns .mac_loop + test byte [e3c59x_full_bus_master], 0xff + jz .set_preamble +; switch to register window 2 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+2 + out dx, ax +; activate xcvr by setting some magic bits + lea edx, [ebp+E3C59X_REG_RESET_OPTIONS] + in ax, dx + and ax, not 0x4010 + movzx ebx, byte [e3c59x_ver_id] + test word [ebx*4+e3c59x_hw_versions+2], INVERT_LED_PWR + jz @f + or al, 0x10 +@@: + test word [ebx*4+e3c59x_hw_versions+2], INVERT_MII_PWR + jz @f + or ah, 0x40 +@@: + out dx, ax +.set_preamble: +; use preamble as default + mov byte [e3c59x_preamble], 1 ; enable preamble + +;*************************************************************************** +; Function +; e3c59x_reset +; Description +; Place the chip (ie, the ethernet card) into a virgin state +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;*************************************************************************** +e3c59x_reset: +; issue global reset + call e3c59x_global_reset +; disable interrupts + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, (1110b shl 11) + out dx, ax +; enable Statistics + mov ax, (10101b shl 11) + out dx, ax +; set indication + mov ax, (1111b shl 11) or 0x6c6 + out dx, ax +; acknowledge (clear) every interrupt indicator + mov ax, (1101b shl 11) or 0x661 + out dx, ax +; switch to register window 2 + mov ax, E3C59X_SELECT_REGISTER_WINDOW+2 + out dx, ax +; write MAC addres back into the station address registers + lea edx, [ebp+E3C59X_REG_STATION_ADDRESS_LO] + mov esi, node_addr + cld + outsw + add edx, 2 + outsw + add edx, 2 + outsw + add edx, 2 +; clear station mask + xor eax, eax + out dx, ax + add edx, 2 + out dx, ax + add edx, 2 + out dx, ax +; switch to register window 6 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+6 + out dx, ax +; clear all statistics by reading + lea edx, [ebp+E3C59X_REG_CARRIER_LOST] + mov cl, 9 +.stat_clearing_loop: + in al, dx + inc edx + dec cl + jns .stat_clearing_loop + in ax, dx + add dx, 2 + in ax, dx +; switch to register window 4 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 + out dx, ax +; clear BadSSD + lea edx, [ebp+E3C59X_REG_BAD_SSD] + in al, dx +; clear extra statistics bit in NetworkDiagnostic + lea edx, [ebp+E3C59X_REG_NETWORK_DIAGNOSTIC] + in ax, dx + or ax, 0x0040 + out dx, ax +; SetRxEarlyThreshold + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, (10001b shl 11)+(E3C59X_MAX_ETH_PKT_SIZE shr 2) + out dx, ax + test byte [e3c59x_full_bus_master], 0xff + jz .skip_boomerang_setting +; set upRxEarlyEnable + lea edx, [ebp+E3C59X_REG_DMA_CTRL] + in eax, dx + or eax, 0x20 + out dx, eax +; TxFreeThreshold + lea edx, [ebp+E3C59X_REG_TX_FREE_THRESH] + mov al, (E3C59X_MAX_ETH_PKT_SIZE / 256) + out dx, al +; program DnListPtr + lea edx, [ebp+E3C59X_REG_DN_LIST_PTR] + xor eax, eax + out dx, eax +.skip_boomerang_setting: +; initialization + call e3c59x_rx_reset + call e3c59x_tx_reset + call e3c59x_set_active_port + call e3c59x_rx_reset + call e3c59x_tx_reset +; switch to register window 5 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+5 + out dx, ax +; program RxFilter for promiscuous operation + mov ax, (10000b shl 11) + lea edx, [ebp+E3C59X_REG_RX_FILTER] + in al, dx + or al, 1111b + lea edx, [ebp+E3C59X_REG_COMMAND] + out dx, ax +; switch to register window 4 + mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 + out dx, ax +; wait for linkDetect + lea edx, [ebp+E3C59X_REG_MEDIA_STATUS] + mov cl, 20 ; wait for max 2s + mov esi, 100 ; 100ms +.link_detect_loop: + call delay_ms + in ax, dx + test ah, 1000b ; linkDetect + jnz @f + dec cl + jnz .link_detect_loop +@@: +; Indicate that we have successfully reset the card + mov eax, [pci_data] + mov [eth_status], eax +if defined E3C59X_DEBUG + call e3c59x_debug +end if ; defined E3C59X_DEBUG + ret + +;*************************************************************************** +; Function +; e3c59x_global_reset +; Description +; resets the device +; Parameters: +; ebp - io_addr +; Return value: +; Destroyed registers +; ax, ecx, edx, esi +; +;*************************************************************************** + align 4 +e3c59x_global_reset: +; GlobalReset + lea edx, [ebp+E3C59X_REG_COMMAND] + xor eax, eax +; or al, 0x14 + out dx, ax +; wait for GlobalReset to complete + mov ecx, 64000 +.global_reset_loop: + in ax, dx + test ah, 10000b ; check CmdInProgress + jz .finish + dec ecx + jnz .global_reset_loop +.finish: +; wait for 2 seconds for NIC to boot + mov esi, 2000 ; 2000ms = 2s + push ebp + call delay_ms + pop ebp + ret + +;*************************************************************************** +; Function +; e3c59x_tx_reset +; Description +; resets and enables transmitter engine +; Parameters: +; ebp - io_addr +; Return value: +; Destroyed registers +; ax, ecx, edx +; +;*************************************************************************** + align 4 +e3c59x_tx_reset: +; TxReset + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, (01011b shl 11) + out dx, ax +; wait for TxReset to complete + mov ecx, 2000 +.tx_reset_loop: + in ax, dx + test ah, 10000b ; check CmdInProgress + jz .tx_enable + dec ecx + jns .tx_reset_loop + test byte [e3c59x_full_bus_master], 0xff + jz .tx_enable +; init last_dpd + mov dword [e3c59x_prev_dpd], e3c59x_dpd_buff+(E3C59X_NUM_TX_DESC-1)*E3C59X_DPD_SIZE + mov dword [e3c59x_prev_tx_frame], e3c59x_tx_buff+(E3C59X_NUM_TX_DESC-1)*E3C59X_MAX_ETH_FRAME_SIZE +.tx_enable: + mov ax, (01001b shl 11) ; TxEnable + out dx, ax + ret + +;*************************************************************************** +; Function +; e3c59x_rx_reset +; Description +; resets and enables receiver engine +; Parameters: +; ebp - io_addr +; Return value: +; Destroyed registers +; eax, ebx, ecx, edx, edi, esi +; +;*************************************************************************** + align 4 +e3c59x_rx_reset: + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, (0101b shl 11) or 0x4 ; RxReset + out dx, ax +; wait for RxReset to complete + mov ecx, 200000 +.rx_reset_loop: + in ax, dx + test ah, 10000b ; check CmdInProgress + jz .setup_upd + dec ecx + jns .rx_reset_loop +.setup_upd: +; check if full bus mastering + test byte [e3c59x_full_bus_master], 0xff + jz .rx_enable +; create upd ring + mov eax, e3c59x_upd_buff + zero_to_virt eax + mov [e3c59x_curr_upd], eax + mov esi, eax + virt_to_dma esi + mov edi, e3c59x_rx_buff + zero_to_dma edi + mov ebx, e3c59x_upd_buff+(E3C59X_NUM_RX_DESC-1)*E3C59X_UPD_SIZE + zero_to_virt ebx + mov cl, E3C59X_NUM_RX_DESC-1 +.upd_loop: + mov [ebx+E3C59X_UPD_UP_NEXT_PTR], esi + and dword [eax+E3C59X_UPD_PKT_STATUS], 0 + mov [eax+E3C59X_UPD_UP_FRAG_ADDR], edi + mov dword [eax+E3C59X_UPD_UP_FRAG_LEN], E3C59X_MAX_ETH_FRAME_SIZE or (1 shl 31) + add edi, E3C59X_MAX_ETH_FRAME_SIZE + add esi, E3C59X_UPD_SIZE + mov ebx, eax + add eax, E3C59X_UPD_SIZE + dec cl + jns .upd_loop + mov eax, e3c59x_upd_buff + zero_to_dma eax + lea edx, [ebp+E3C59X_REG_UP_LIST_PTR] + out dx, eax ; write E3C59X_REG_UP_LIST_PTR + lea edx, [ebp+E3C59X_REG_COMMAND] +.rx_enable: + mov ax, (00100b shl 11) ; RxEnable + out dx, ax + ret + +;*************************************************************************** +; Function +; e3c59x_write_eeprom +; Description +; reads eeprom +; Note : the caller must switch to the register window 0 +; before calling this function +; Parameters: +; ax - register to be read (only the first 63 words can be read) +; cx - value to be read into the register +; Return value: +; ax - word read +; Destroyed registers +; ax, ebx, edx +; +;*************************************************************************** +; align 4 +;e3c59x_write_eeprom: +; mov edx, [io_addr] +; add edx, E3C59X_REG_EEPROM_COMMAND +; cmp ah, 11b +; ja .finish ; address may have a value of maximal 1023 +; shl ax, 2 +; shr al, 2 +; push eax +;; wait for busy +; mov ebx, 0xffff +;@@: +; in ax, dx +; test ah, 0x80 +; jz .write_enable +; dec ebx +; jns @r +;; write enable +;.write_enable: +; xor eax, eax +; mov eax, (11b shl 4) +; out dx, ax +;; wait for busy +; mov ebx, 0xffff +;@@: +; in ax, dx +; test ah, 0x80 +; jz .erase_loop +; dec ebx +; jns @r +;.erase_loop: +; pop eax +; push eax +; or ax, (11b shl 6) ; erase register +; out dx, ax +; mov ebx, 0xffff +;@@: +; in ax, dx +; test ah, 0x80 +; jz .write_reg +; dec ebx +; jns @r +;.write_reg: +; add edx, E3C59X_REG_EEPROM_DATA-E3C59X_REG_EEPROM_COMMAND +; mov eax, ecx +; out dx, ax +;; write enable +; add edx, E3C59X_REG_EEPROM_COMMAND-E3C59X_REG_EEPROM_DATA +; xor eax, eax +; mov eax, (11b shl 4) +; out dx, ax +; wait for busy +; mov ebx, 0xffff +;@@: +; in ax, dx +; test ah, 0x80 +; jz .issue_write_reg +; dec ebx +; jns @r +;.issue_write_reg: +; pop eax +; or ax, 01b shl 6 +; out dx, ax +;.finish: +; ret +;*************************************************************************** +; Function +; e3c59x_read_eeprom +; Description +; reads eeprom +; Parameters: +; ax - register to be read (only the first 63 words can be read) +; ebp - io_addr +; Return value: +; ax - word read +; Destroyed registers +; ax, ebx, edx, ebp +; +;*************************************************************************** + align 4 +e3c59x_read_eeprom: + push eax +; switch to register window 0 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+0 + out dx, ax + pop eax + and ax, 111111b ; take only the first 6 bits into account + movzx ebx, byte [e3c59x_ver_id] + test word [ebx*4+e3c59x_hw_versions+2], EEPROM_8BIT + jz @f + add ax, 0x230 ; hardware constant + jmp .read +@@: + add ax, E3C59X_EEPROM_CMD_READ + test word [ebx*4+e3c59x_hw_versions+2], EEPROM_OFFSET + jz .read + add ax, 0x30 +.read: + lea edx, [ebp+E3C59X_REG_EEPROM_COMMAND] + out dx, ax + mov ebx, 0xffff ; duration of about 162 us ;-) +.wait_for_reading: + in ax, dx + test ah, 0x80 ; check bit eepromBusy + jz .read_data + dec ebx + jns .wait_for_reading +.read_data: + lea edx, [ebp+E3C59X_REG_EEPROM_DATA] + in ax, dx + ret + +;*************************************************************************** +; Function +; e3c59x_mdio_sync +; Description +; initial synchronization +; Parameters +; ebp - io_addr +; Return value +; Destroyed registers +; ax, edx, cl +; +;*************************************************************************** + align 4 +e3c59x_mdio_sync: +; switch to register window 4 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+4 + out dx, ax + cmp byte [e3c59x_preamble], 0 + je .no_preamble +; send 32 logic ones + lea edx, [ebp+E3C59X_REG_PHYSICAL_MGMT] + mov cl, 31 +.loop: + mov ax, (1 shl E3C59X_BIT_MGMT_DATA) or (1 shl E3C59X_BIT_MGMT_DIR) + out dx, ax + in ax, dx ; delay + mov ax, (1 shl E3C59X_BIT_MGMT_DATA) \ + or (1 shl E3C59X_BIT_MGMT_DIR) \ + or (1 shl E3C59X_BIT_MGMT_CLK) + out dx, ax + in ax, dx ; delay + dec cl + jns .loop +.no_preamble: + ret + +;*************************************************************************** +; Function +; e3c59x_mdio_read +; Description +; read MII register +; see page 16 in D83840A.pdf +; Parameters +; ah - PHY addr +; al - register addr +; ebp - io_addr +; Return value +; ax - register read +; Destroyed registers +; eax, ebx, cx, edx +; +;*************************************************************************** + align 4 +e3c59x_mdio_read: + push eax + call e3c59x_mdio_sync ; returns with window #4 + pop eax + lea edx, [ebp+E3C59X_REG_PHYSICAL_MGMT] + shl al, 3 + shr ax, 3 + and ax, not E3C59X_MII_CMD_MASK + or ax, E3C59X_MII_CMD_READ + mov ebx, eax + xor ecx, ecx + mov cl, 13 +.cmd_loop: + mov ax, (1 shl E3C59X_BIT_MGMT_DIR) ; write mii + bt ebx, ecx + jnc .zero_bit + or al, (1 shl E3C59X_BIT_MGMT_DATA) +.zero_bit: + out dx, ax + push eax + in ax, dx ; delay + pop eax + or al, (1 shl E3C59X_BIT_MGMT_CLK) ; write + out dx, ax + in ax, dx ; delay + dec cl + jns .cmd_loop +; read data (18 bits with the two transition bits) + mov cl, 17 + xor ebx, ebx +.read_loop: + shl ebx, 1 + xor eax, eax ; read comand + out dx, ax + in ax, dx ; delay + in ax, dx + test al, (1 shl E3C59X_BIT_MGMT_DATA) + jz .dont_set + inc ebx +.dont_set: + mov ax, (1 shl E3C59X_BIT_MGMT_CLK) + out dx, ax + in ax, dx ; delay + dec cl + jns .read_loop + mov eax, ebx + ret + +;*************************************************************************** +; Function +; e3c59x_mdio_write +; Description +; write MII register +; see page 16 in D83840A.pdf +; Parameters +; ah - PHY addr +; al - register addr +; bx - word to be written +; ebp - io_addr +; Return value +; ax - register read +; Destroyed registers +; eax, ebx, cx, edx +; +;*************************************************************************** + align 4 +e3c59x_mdio_write: + push eax + call e3c59x_mdio_sync + pop eax + lea edx, [ebp+E3C59X_REG_PHYSICAL_MGMT] + shl al, 3 + shr ax, 3 + and ax, not E3C59X_MII_CMD_MASK + or ax, E3C59X_MII_CMD_WRITE + shl eax, 2 + or eax, 10b ; transition bits + shl eax, 16 + mov ax, bx + mov ebx, eax + mov ecx, 31 +.cmd_loop: + mov ax, (1 shl E3C59X_BIT_MGMT_DIR) ; write mii + bt ebx, ecx + jnc .zero_bit + or al, (1 shl E3C59X_BIT_MGMT_DATA) +.zero_bit: + out dx, ax + push eax + in ax, dx ; delay + pop eax + or al, (1 shl E3C59X_BIT_MGMT_CLK) ; write + out dx, ax + in ax, dx ; delay + dec ecx + jns .cmd_loop + ret + +;*************************************************************************** +; Function +; e3c59x_transmit +; Description +; Transmits a packet of data via the ethernet card +; edi - Pointer to 48 bit destination address +; bx - Type of packet +; ecx - size of packet +; esi - pointer to packet data +; ebp - io_addr +; Destroyed registers +; eax, ecx, edx, ebp +; +;*************************************************************************** + align 4 +e3c59x_transmit: + jmp dword [e3c59x_transmit_function] + +;*************************************************************************** +; Function +; e3c59x_check_tx_status +; Description +; Checks TxStatus queue. +; Return value +; al - 0 no error was found +; al - 1 error was found TxReset is needed +; Destroyed registers +; eax, ecx, edx, ebp +; +;*************************************************************************** +e3c59x_check_tx_status: + movzx ebp, word [io_addr] ; to be implemented in ETHERNET.INC +; clear TxStatus queue + lea edx, [ebp+E3C59X_REG_TX_STATUS] + mov cl, 31 ; max number of queue entries +.tx_status_loop: + in al, dx + test al, al + jz .finish ; no error + test al, 0x3f + jnz .finish ; error +.no_error_found: +; clear current TxStatus entry which advances the next one + xor al, al + out dx, al + dec cl + jns .tx_status_loop +.finish: + ret + +;*************************************************************************** +; Function +; e3c59x_vortex_transmit +; Description +; Transmits a packet of data via the ethernet card +; edi - Pointer to 48 bit destination address +; bx - Type of packet +; ecx - size of packet +; esi - pointer to packet data +; ebp - io_addr +; Destroyed registers +; eax, edx, ecx, edi, esi, ebp +; +;*************************************************************************** + align 4 +e3c59x_vortex_transmit: + push ecx + call e3c59x_check_tx_status + pop ecx + test al, al + jz .no_error_found + jmp e3c59x_tx_reset +.no_error_found: +; switch to register window 7 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+7 + out dx, ax +; check for master operation in progress + lea edx, [ebp+E3C59X_REG_MASTER_STATUS] + in ax, dx + test ah, 0x80 + jnz .finish ; no DMA for sending +; dword boundary correction + cmp ecx, E3C59X_MAX_ETH_FRAME_SIZE + ja .finish ; packet is too long +; write Frame Start Header + mov eax, ecx +; add header length and extend the complete length to dword boundary + add eax, ETH_HLEN+3 + and eax, not 3 + lea edx, [ebp+E3C59X_REG_TX_DATA] + out dx, eax +; prepare the complete frame + push esi + mov esi, edi + mov edi, e3c59x_tx_buff + zero_to_virt edi + cld +; copy destination address + movsd + movsw +; copy source address + mov esi, node_addr + movsd + movsw +; copy packet type + mov [edi], bx + add edi, 2 +; copy packet data + pop esi + push ecx + shr ecx, 2 + rep movsd + pop ecx + and ecx, 3 + rep movsb + mov ecx, eax +; program frame address to be sent + lea edx, [ebp+E3C59X_REG_MASTER_ADDRESS] + mov eax, e3c59x_tx_buff + zero_to_dma eax + out dx, eax +; program frame length + lea edx, [ebp+E3C59X_REG_MASTER_LEN] + mov eax, ecx + out dx, ax +; start DMA Down + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, (10100b shl 11) + 1 ; StartDMADown + out dx, ax +.finish: + ret + +;*************************************************************************** +; Function +; e3c59x_boomerang_transmit +; Description +; Transmits a packet of data via the ethernet card +; edi - Pointer to 48 bit destination address +; bx - Type of packet +; ecx - size of packet +; esi - pointer to packet data +; ebp - io_addr +; Destroyed registers +; eax, ebx, ecx, edx, esi, edi, ebp +; +;*************************************************************************** + align 4 +e3c59x_boomerang_transmit: + push ecx + call e3c59x_check_tx_status + pop ecx + test al, al + jz .no_error_found + jmp e3c59x_tx_reset +.no_error_found: + cmp ecx, E3C59X_MAX_ETH_FRAME_SIZE + ja .finish ; packet is too long +; calculate descriptor address + mov eax, [e3c59x_prev_dpd] + cmp eax, e3c59x_dpd_buff+(E3C59X_NUM_TX_DESC-1)*E3C59X_DPD_SIZE + jb @f +; wrap around + mov eax, e3c59x_dpd_buff-E3C59X_DPD_SIZE +@@: + add eax, E3C59X_DPD_SIZE + zero_to_virt eax + push eax +; check DnListPtr + lea edx, [ebp+E3C59X_REG_DN_LIST_PTR] + in eax, dx +; mark if Dn_List_Ptr is cleared + test eax, eax + setz [e3c59x_dn_list_ptr_cleared] +; finish if no more free descriptor is available - FIXME! + cmp eax, [esp] + pop eax + jz .finish + push eax esi + mov esi, edi +; calculate tx_buffer address + mov edi, [e3c59x_prev_tx_frame] + cmp edi, e3c59x_tx_buff+(E3C59X_NUM_TX_DESC-1)*E3C59X_MAX_ETH_FRAME_SIZE + jb @f +; wrap around + mov edi, e3c59x_tx_buff-E3C59X_MAX_ETH_FRAME_SIZE +@@: + add edi, E3C59X_MAX_ETH_FRAME_SIZE + zero_to_virt edi + mov eax, edi + cld +; copy destination address + movsd + movsw +; copy source address + mov esi, node_addr + movsd + movsw +; copy packet type + mov [edi], bx + add edi, 2 +; copy packet data + pop esi + push ecx + shr ecx, 2 + rep movsd + pop ecx + push ecx + and ecx, 3 + rep movsb +; padding, do we really need it? + pop ecx + add ecx, ETH_HLEN + cmp ecx, ETH_ZLEN + jae @f + mov ecx, ETH_ZLEN +@@: +; calculate + mov ebx, ecx + test byte [e3c59x_has_hwcksm], 0xff + jz @f + or ebx, (1 shl 26) ; set AddTcpChecksum +@@: + or ebx, 0x8000 ; transmission complete notification + or ecx, 0x80000000 ; last fragment +; program DPD + mov edi, eax + pop eax + and dword [eax+E3C59X_DPD_DN_NEXT_PTR], 0 + mov dword [eax+E3C59X_DPD_FRAME_START_HDR], ebx + virt_to_dma edi + mov dword [eax+E3C59X_DPD_DN_FRAG_ADDR], edi + mov [eax+E3C59X_DPD_DN_FRAG_LEN], ecx +; calculate physical address + virt_to_dma eax + push eax + cmp byte [e3c59x_dn_list_ptr_cleared], 0 + jz .add_to_list +; write Dn_List_Ptr + out dx, eax + jmp .finish +.add_to_list: +; DnStall + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, ((110b shl 11)+2) + out dx, ax +; wait for DnStall to complete + mov ecx, 6000 +.wait_for_stall: + in ax, dx ; read E3C59X_REG_INT_STATUS + test ah, 10000b + jz .dnstall_ok + dec ecx + jnz .wait_for_stall +.dnstall_ok: + pop eax + push eax + mov ebx, [e3c59x_prev_dpd] + zero_to_virt ebx + mov [ebx], eax + lea edx, [ebp+E3C59X_REG_DN_LIST_PTR] + in eax, dx + test eax, eax + jnz .dnunstall +; if Dn_List_Ptr has been cleared fill it up + pop eax + push eax + out dx, eax +.dnunstall: +; DnUnStall + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, ((110b shl 11)+3) + out dx, ax +.finish: + pop eax + dma_to_zero eax + mov [e3c59x_prev_dpd], eax + dma_to_zero edi + mov [e3c59x_prev_tx_frame], edi + ret + +;*************************************************************************** +; Function +; e3c59x_poll +; Description +; Polls the ethernet card for a received packet +; Received data, if any, ends up in Ether_buffer +; Destroyed registers +; eax, ebx, edx, ecx, edi, esi, ebp +; +;*************************************************************************** + align 4 +e3c59x_poll: + jmp dword [e3c59x_receive_function] + +;*************************************************************************** +; Function +; e3c59x_vortex_poll +; Description +; Polls the ethernet card for a received packet +; Received data, if any, ends up in Ether_buffer +; Parameters +; ebp - io_addr +; Return value +; al - 0 ; no packet received +; al - 1 ; packet received +; Destroyed registers +; eax, ebx, edx, ecx, edi, esi, ebp +; +;*************************************************************************** + align 4 +e3c59x_vortex_poll: + and word [eth_rx_data_len], 0 ; assume no packet received + movzx ebp, word [io_addr] ; to be implemented in ETHERNET.INC +.rx_status_loop: +; examine RxStatus + lea edx, [ebp+E3C59X_REG_RX_STATUS] + in ax, dx + test ax, ax + jz .finish + test ah, 0x80 ; rxIncomplete + jz .check_error + jmp .finish +.check_error: + test ah, 0x40 + jz .check_length +; discard the top frame received advancing the next one + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, (01000b shl 11) + out dx, ax + jmp .rx_status_loop +.check_length: + and eax, 0x1fff + cmp eax, E3C59X_MAX_ETH_PKT_SIZE + ja .discard_frame ; frame is too long discard it +.check_dma: + push eax +; switch to register window 7 + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, E3C59X_SELECT_REGISTER_WINDOW+7 + out dx, ax +; check for master operation in progress + lea edx, [ebp+E3C59X_REG_MASTER_STATUS] + in ax, dx + test ah, 0x80 + jz .read_frame ; no DMA for receiving + pop eax + jmp .finish +.read_frame: +; program buffer address to read in + lea edx, [ebp+E3C59X_REG_MASTER_ADDRESS] +if defined E3C59X_LINUX + mov eax, e3c59x_rx_buff + zero_to_dma eax +else + mov eax, Ether_buffer +end if + out dx, eax +; program frame length + lea edx, [ebp+E3C59X_REG_MASTER_LEN] + mov ax, 1560 + out dx, ax +; start DMA Up + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, (10100b shl 11) ; StartDMAUp + out dx, ax +; check for master operation in progress +.dma_loop: + lea edx, [ebp+E3C59X_REG_MASTER_STATUS] + in ax, dx + test ah, 0x80 + jnz .dma_loop +; registrate the received packet length + pop eax + mov word [eth_rx_data_len], ax +; discard the top frame received +.discard_frame: + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, (01000b shl 11) + out dx, ax +.finish: +; set return value + cmp word [eth_rx_data_len], 0 + setne al + ret + +;*************************************************************************** +; Function +; e3c59x_boomerang_poll +; Description +; Polls the ethernet card for a received packet +; Received data, if any, ends up in Ether_buffer +; Parameters +; ebp - io_addr +; Return value +; al - 0 ; no packet received +; al - 1 ; packet received +; Destroyed registers +; eax, edx, ecx, edi, esi, ebp +; +;*************************************************************************** + align 4 +e3c59x_boomerang_poll: + and word [eth_rx_data_len], 0 ; assume no packet received + movzx ebp, word [io_addr] ; to be implemented in ETHERNET.INC +; check if packet is uploaded + mov eax, [e3c59x_curr_upd] + test byte [eax+E3C59X_UPD_PKT_STATUS+1], 0x80 ; upPktComplete + jnz .check_error + jmp .finish +; packet is uploaded check for any error +.check_error: + test byte [eax+E3C59X_UPD_PKT_STATUS+1], 0x40 ; upError + jz .copy_packet_length + and dword [eax+E3C59X_UPD_PKT_STATUS], 0 + jmp .finish +.copy_packet_length: + mov ecx, [eax+E3C59X_UPD_PKT_STATUS] + and ecx, 0x1fff + cmp ecx, E3C59X_MAX_ETH_PKT_SIZE + jbe .copy_packet + and dword [eax+E3C59X_UPD_PKT_STATUS], 0 + jmp .finish +.copy_packet: + push ecx + mov word [eth_rx_data_len], cx + mov esi, [eax+E3C59X_UPD_UP_FRAG_ADDR] + dma_to_virt esi + mov edi, Ether_buffer + shr ecx, 2 ; first copy dword-wise + cld + rep movsd ; copy the dwords + pop ecx + and ecx, 3 + rep movsb ; copy the rest bytes + mov eax, [e3c59x_curr_upd] + and dword [eax+E3C59X_UPD_PKT_STATUS], 0 + virt_to_zero eax + cmp eax, e3c59x_upd_buff+(E3C59X_NUM_RX_DESC-1)*E3C59X_UPD_SIZE + jb .no_wrap +; wrap around + mov eax, e3c59x_upd_buff-E3C59X_UPD_SIZE +.no_wrap: + add eax, E3C59X_UPD_SIZE + zero_to_virt eax + mov [e3c59x_curr_upd], eax +.finish: +; check if the NIC is in the upStall state + lea edx, [ebp+E3C59X_REG_UP_PKT_STATUS] + in eax, dx + test ah, 0x20 ; UpStalled + jz .noUpUnStall +; issue upUnStall command + lea edx, [ebp+E3C59X_REG_COMMAND] + mov ax, ((110b shl 11)+1) ; upUnStall + out dx, ax +.noUpUnStall: +; set return value + cmp word [eth_rx_data_len], 0 + setnz al + ret diff --git a/kernel/trunk/network/eth_drv/drivers/i8255x.inc b/kernel/trunk/network/eth_drv/drivers/i8255x.inc new file mode 100644 index 0000000000..2aeb86414b --- /dev/null +++ b/kernel/trunk/network/eth_drv/drivers/i8255x.inc @@ -0,0 +1,739 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; I8255X.INC ;; +;; ;; +;; Ethernet driver for Menuet OS ;; +;; ;; +;; Version 0.3 11 August 2003 ;; +;; ;; +;; This driver is based on the eepro100 driver from ;; +;; the etherboot 5.0.6 project. The copyright statement is ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;; remaining parts Copyright 2002 Mike Hibbett, ;; +;; mikeh@oceanfree.net ;; +;; ;; +;; See file COPYING for details ;; +;; ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +;******************************************************************** +; Interface +; I8255x_reset +; I8255x_probe +; I8255x_poll +; I8255x_transmit +; +; These functions are referenced in ethernet.inc +; +;******************************************************************** + + +rxfd_status equ eth_data_start +rxfd_command equ eth_data_start + 2 +rxfd_link equ eth_data_start + 4 +rxfd_rx_buf_addr equ eth_data_start + 8 +rxfd_count equ eth_data_start + 12 +rxfd_size equ eth_data_start + 14 +rxfd_packet equ eth_data_start + 16 + + + +uglobal +eeprom_data: times 16 dd 0 + +align 4 + +lstats: +tx_good_frames: dd 0 +tx_coll16_errs: dd 0 +tx_late_colls: dd 0 +tx_underruns: dd 0 +tx_lost_carrier: dd 0 +tx_deferred: dd 0 +tx_one_colls: dd 0 +tx_multi_colls: dd 0 +tx_total_colls: dd 0 +rx_good_frames: dd 0 +rx_crc_errs: dd 0 +rx_align_errs: dd 0 +rx_resource_errs: dd 0 +rx_overrun_errs: dd 0 +rx_colls_errs: dd 0 +rx_runt_errs: dd 0 +done_marker: dd 0 + +align 4 + +confcmd: +confcmd_status: dw 0 +confcmd_command: dw 0 +confcmd_link: dd 0 +endg + +iglobal +confcmd_data: db 22, 0x08, 0, 0, 0, 0x80, 0x32, 0x03, 1 + db 0, 0x2e, 0, 0x60, 0, 0xf2, 0x48, 0, 0x40, 0xf2 + db 0x80, 0x3f, 0x05 +endg + +uglobal +align 4 + +txfd: +txfd_status: dw 0 +txfd_command: dw 0 +txfd_link: dd 0 +txfd_tx_desc_addr: dd 0 +txfd_count: dd 0 +txfd_tx_buf_addr0: dd 0 +txfd_tx_buf_size0: dd 0 +txfd_tx_buf_addr1: dd 0 +txfd_tx_buf_size1: dd 0 + +align 4 + +hdr: +hdr_dst_addr: times 6 db 0 +hdr_src_addr: times 6 db 0 +hdr_type: dw 0 +endg + + +;*************************************************************************** +; Function +; wait_for_cmd_done +; +; Description +; waits for the hardware to complete a command +; port address in edx +; +; al destroyed +;*************************************************************************** +wait_for_cmd_done: + in al, dx + cmp al, 0 + jne wait_for_cmd_done + ret + + + +;*************************************************************************** +; Function +; mdio_read +; +; Description +; This probably reads a register in the "physical media interface chip" +; Phy_id in ebx +; location in ecx +; +; Data returned in eax +; +;*************************************************************************** +mdio_read: + mov edx, [io_addr] + add edx, 16 ; SCBCtrlMDI + + mov eax, 0x08000000 + shl ecx, 16 + or eax, ecx + shl ebx, 21 + or eax, ebx + + out dx, eax + +mrlp: + call delay_us + in eax, dx + mov ecx, eax + and ecx, 0x10000000 + jz mrlp + + and eax, 0xffff + ret + + + +;*************************************************************************** +; Function +; mdio_write +; +; Description +; This probably writes a register in the "physical media interface chip" +; Phy_id in ebx +; location in ecx +; data in edx +; Data returned in eax +; +;*************************************************************************** +mdio_write: + mov eax, 0x04000000 + shl ecx, 16 + or eax, ecx + shl ebx, 21 + or eax, ebx + or eax, edx + + mov edx, [io_addr] + add edx, 16 ; SCBCtrlMDI + out dx, eax + +mwlp: + call delay_us + in eax, dx + mov ecx, eax + and ecx, 0x10000000 + jz mwlp + + and eax, 0xffff + ret + + + +;/***********************************************************************/ +;/* I82557 related defines */ +;/***********************************************************************/ + +; Serial EEPROM section. +; A "bit" grungy, but we work our way through bit-by-bit :->. +; EEPROM_Ctrl bits. +EE_SHIFT_CLK equ 0x01 ; EEPROM shift clock. +EE_CS equ 0x02 ; EEPROM chip select. +EE_DATA_WRITE equ 0x04 ; EEPROM chip data in. +EE_DATA_READ equ 0x08 ; EEPROM chip data out. +EE_WRITE_0 equ 0x4802 +EE_WRITE_1 equ 0x4806 +EE_ENB equ 0x4802 + + +; The EEPROM commands include the alway-set leading bit. +EE_READ_CMD equ 6 + +; The SCB accepts the following controls for the Tx and Rx units: +CU_START equ 0x0010 +CU_RESUME equ 0x0020 +CU_STATSADDR equ 0x0040 +CU_SHOWSTATS equ 0x0050 ; Dump statistics counters. +CU_CMD_BASE equ 0x0060 ; Base address to add to add CU commands. +CU_DUMPSTATS equ 0x0070 ; Dump then reset stats counters. + +RX_START equ 0x0001 +RX_RESUME equ 0x0002 +RX_ABORT equ 0x0004 +RX_ADDR_LOAD equ 0x0006 +RX_RESUMENR equ 0x0007 +INT_MASK equ 0x0100 +DRVR_INT equ 0x0200 ; Driver generated interrupt. + + +;*************************************************************************** +; Function +; do_eeprom_cmd +; +; Description +; writes a cmd to the ethernet cards eeprom, by bit bashing +; cmd in ebx +; cmd length in ecx +; return in eax +;*************************************************************************** +do_eeprom_cmd: + mov edx, [io_addr] ; We only require the value in dx + add dx, 14 ; the value SCBeeprom + + mov ax, EE_ENB + out dx, ax + call delay_us + + mov ax, 0x4803 ; EE_ENB | EE_SHIFT_CLK + out dx, ax + call delay_us + + ; dx holds ee_addr + ; ecx holds count + ; eax holds cmd + xor edi, edi ; this will be the receive data + +dec_001: + mov esi, 1 + + dec ecx + shl esi, cl + inc ecx + and esi, ebx + mov eax, EE_WRITE_0 ; I am assuming this doesnt affect the flags.. + cmp esi,0 + jz dec_002 + mov eax, EE_WRITE_1 + +dec_002: + out dx, ax + call delay_us + + or ax, EE_SHIFT_CLK + out dx, ax + call delay_us + + shl edi,1 + + in ax, dx + and ax, EE_DATA_READ + cmp ax,0 + jz dec_003 + inc edi + +dec_003: + loop dec_001 + + mov ax, EE_ENB + out dx, ax + call delay_us + + mov ax, 0x4800 + out dx, ax + call delay_us + + mov eax, edi + + ret + + + +;*************************************************************************** +; Function +; I8255x_reset +; Description +; Place the chip (ie, the ethernet card) into a virgin state +; No inputs +; All registers destroyed +; +;*************************************************************************** +I8255x_reset: + ret + + + +;*************************************************************************** +; Function +; I8255x_probe +; Description +; Searches for an ethernet card, enables it and clears the rx buffer +; If a card was found, it enables the ethernet -> TCPIP link +; +;*************************************************************************** +I8255x_probe: + mov eax, [io_addr] + + mov ebx, [pci_bus] + mov ecx, [pci_dev] + mov edx, 0x04 ; PCI_COMMAND + call pcibios_read_config_word + + or ax, 0x05 + mov ebx, [pci_bus] + mov ecx, [pci_dev] + mov edx, 0x04 ; PCI_COMMAND + call pcibios_write_config_word + + mov ebx, 0x6000000 + mov ecx, 27 + call do_eeprom_cmd + and eax, 0xffe0000 + cmp eax, 0xffe0000 + je bige + + mov ebx, 0x1800000 + mov ecx, 0x40 + jmp doread + +bige: + mov ebx, 0x6000000 + mov ecx, 0x100 + +doread: + ; do-eeprom-cmd will destroy all registers + ; we have eesize in ecx + ; read_cmd in ebx + + ; Ignore full eeprom - just load the mac address + mov ecx, 0 + +drlp: + push ecx ; save count + push ebx + mov eax, ecx + shl eax, 16 + or ebx, eax + mov ecx, 27 + call do_eeprom_cmd + + pop ebx + pop ecx + + mov edx, ecx + shl edx, 2 + mov esi, eeprom_data + add esi, edx + mov [esi], eax + + inc ecx + cmp ecx, 16 + jne drlp + + ; OK, we have the MAC address. + ; Now reset the card + + mov edx, [io_addr] + add dx, 8 ; SCBPort + xor eax, eax ; The reset cmd == 0 + out dx, eax + + mov esi, 10 + call delay_ms ; Give the card time to warm up. + + mov eax, lstats + mov edx, [io_addr] + add edx, 4 ; SCBPointer + out dx, eax + + mov eax, 0x0140 ; INT_MASK | CU_STATSADDR + mov edx, [io_addr] + add edx, 2 ; SCBCmd + out dx, ax + + call wait_for_cmd_done + + mov eax, 0 + mov edx, [io_addr] + add edx, 4 ; SCBPointer + out dx, eax + + mov eax, 0x0106 ; INT_MASK | RX_ADDR_LOAD + mov edx, [io_addr] + add edx, 2 ; SCBCmd + out dx, ax + + call wait_for_cmd_done + + ; build rxrd structure + mov ax, 0x0001 + mov [rxfd_status], ax + mov ax, 0x0000 + mov [rxfd_command], ax + + mov eax, rxfd_status + mov [rxfd_link], eax + + mov eax, Ether_buffer + mov [rxfd_rx_buf_addr], eax + + mov ax, 0 + mov [rxfd_count], ax + + mov ax, 1528 + mov [rxfd_size], ax + + mov edx, [io_addr] + add edx, 4 ; SCBPointer + + mov eax, rxfd_status + out dx, eax + + mov edx, [io_addr] + add edx, 2 ; SCBCmd + + mov ax, 0x0101 ; INT_MASK | RX_START + out dx, ax + + call wait_for_cmd_done + + ; start the reciver + + mov ax, 0 + mov [rxfd_status], ax + + mov ax, 0xc000 + mov [rxfd_command], ax + + mov edx, [io_addr] + add edx, 4 ; SCBPointer + + mov eax, rxfd_status + out dx, eax + + mov edx, [io_addr] + add edx, 2 ; SCBCmd + + mov ax, 0x0101 ; INT_MASK | RX_START + out dx, ax + + ; Init TX Stuff + + mov edx, [io_addr] + add edx, 4 ; SCBPointer + + mov eax, 0 + out dx, eax + + mov edx, [io_addr] + add edx, 2 ; SCBCmd + + mov ax, 0x0160 ; INT_MASK | CU_CMD_BASE + out dx, ax + + call wait_for_cmd_done + + ; Set TX Base address + + ; First, set up confcmd values + + mov ax, 2 + mov [confcmd_command], ax + mov eax, txfd + mov [confcmd_link], eax + + mov ax, 1 + mov [txfd_command], ax ; CmdIASetup + + mov ax, 0 + mov [txfd_status], ax + + mov eax, confcmd + mov [txfd_link], eax + + ; ETH_ALEN is 6 bytes + + mov esi, eeprom_data + mov edi, node_addr + mov ecx, 3 +drp000: + mov eax, [esi] + mov [edi], al + shr eax, 8 + inc edi + mov [edi], al + inc edi + add esi, 4 + loop drp000 + + ; Hard code your MAC address into node_addr at this point, + ; If you cannot read the MAC address from the eeprom in the previous step. + ; You also have to write the mac address into txfd_tx_desc_addr, rather + ; than taking data from eeprom_data + + mov esi, eeprom_data + mov edi, txfd_tx_desc_addr + mov ecx, 3 +drp001: + mov eax, [esi] + mov [edi], al + shr eax, 8 + inc edi + mov [edi], al + inc edi + add esi, 4 + loop drp001 + + mov esi, eeprom_data + (6 * 4) + mov eax, [esi] + shr eax, 8 + and eax, 0x3f + cmp eax, 4 ; DP83840 + je drp002 + cmp eax, 10 ; DP83840A + je drp002 + jmp drp003 + +drp002: + mov ebx, [esi] + and ebx, 0x1f + push ebx + mov ecx, 23 + call mdio_read + pop ebx + or eax, 0x0422 + mov ecx, 23 + mov edx, eax + call mdio_write + +drp003: + mov ax, 0x4002 ; Cmdsuspend | CmdConfigure + mov [confcmd_command], ax + mov ax, 0 + mov [confcmd_status], ax + mov eax, txfd + mov [confcmd_link], eax + mov ebx, confcmd_data + mov al, 0x88 ; fifo of 8 each + mov [ebx + 1], al + mov al, 0 + mov [ebx + 4], al + mov al, 0x80 + mov [ebx + 5], al + mov al, 0x48 + mov [ebx + 15], al + mov al, 0x80 + mov [ebx + 19], al + mov al, 0x05 + mov [ebx + 21], al + + mov eax, txfd + mov edx, [io_addr] + add edx, 4 ; SCBPointer + out dx, eax + + mov eax, 0x0110 ; INT_MASK | CU_START + mov edx, [io_addr] + add edx, 2 ; SCBCmd + out dx, ax + + call wait_for_cmd_done +jmp skip + + ; wait for thing to start +drp004: + mov ax, [txfd_status] + cmp ax, 0 + je drp004 + +skip: + ; Indicate that we have successfully reset the card + mov eax, [pci_data] + mov [eth_status], eax + +I8255x_exit: + ret + + + +;*************************************************************************** +; Function +; I8255x_poll +; +; Description +; Polls the ethernet card for a received packet +; Received data, if any, ends up in Ether_buffer +; +;*************************************************************************** +I8255x_poll: + mov ax, 0 ; assume no data + mov [eth_rx_data_len], ax + + mov ax, [rxfd_status] + cmp ax, 0 + je i8p_exit + + mov ax, 0 + mov [rxfd_status], ax + + mov ax, 0xc000 + mov [rxfd_command], ax + + mov edx, [io_addr] + add edx, 4 ; SCBPointer + + mov eax, rxfd_status + out dx, eax + + mov edx, [io_addr] + add edx, 2 ; SCBCmd + + mov ax, 0x0101 ; INT_MASK | RX_START + out dx, ax + + call wait_for_cmd_done + + mov esi, rxfd_packet + mov edi, Ether_buffer + mov ecx, 1518 + cld + rep movsb + + mov ax, [rxfd_count] + and ax, 0x3fff + mov [eth_rx_data_len], ax + +i8p_exit: + ret + + + +;*************************************************************************** +; Function +; I8255x_transmit +; +; Description +; Transmits a packet of data via the ethernet card +; Pointer to 48 bit destination address in edi +; Type of packet in bx +; size of packet in ecx +; pointer to packet data in esi +; +;*************************************************************************** +I8255x_transmit: + + mov [hdr_type], bx + + mov eax, [edi] + mov [hdr_dst_addr], eax + mov ax, [edi+4] + mov [hdr_dst_addr+4], ax + + mov eax, [node_addr] + mov [hdr_src_addr], eax + mov ax, [node_addr+4] + mov [hdr_src_addr+4], ax + + mov edx, [io_addr] + in ax, dx + and ax, 0xfc00 + out dx, ax + + xor ax, ax + mov [txfd_status], ax + mov ax, 0x400C ; Cmdsuspend | CmdTx | CmdTxFlex + mov [txfd_command], ax + mov eax, txfd + mov [txfd_link], eax + mov eax, 0x02208000 + mov [txfd_count], eax + mov eax, txfd_tx_buf_addr0 + mov [txfd_tx_desc_addr], eax + mov eax, hdr + mov [txfd_tx_buf_addr0], eax + mov eax, 14 ; sizeof hdr + mov [txfd_tx_buf_size0], eax + + ; Copy the buffer address and size in + mov eax, esi + mov [txfd_tx_buf_addr1], eax + mov eax, ecx + mov [txfd_tx_buf_size1], eax + + mov eax, txfd + mov edx, [io_addr] + add edx, 4 ; SCBPointer + out dx, eax + + mov ax, 0x0110 ; INT_MASK | CU_START + mov edx, [io_addr] + add edx, 2 ; SCBCmd + out dx, ax + + call wait_for_cmd_done + + mov edx, [io_addr] + in ax, dx + +I8t_001: + mov ax, [txfd_status] + cmp ax, 0 + je I8t_001 + + mov edx, [io_addr] + in ax, dx + + ret \ No newline at end of file diff --git a/kernel/trunk/network/eth_drv/drivers/pcnet32.inc b/kernel/trunk/network/eth_drv/drivers/pcnet32.inc new file mode 100644 index 0000000000..4f6e3db1ad --- /dev/null +++ b/kernel/trunk/network/eth_drv/drivers/pcnet32.inc @@ -0,0 +1,814 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; PCNET32.INC ;; +;; ;; +;; Ethernet driver for Menuet OS ;; +;; ;; +;; Version 1.0 31 July 2004 ;; +;; ;; +;; This driver is based on the PCNet32 driver from ;; +;; the etherboot 5.0.6 project. The copyright statement is ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;; remaining parts Copyright 2004 Jarek Pelczar, ;; +;; jpelczar@interia.pl ;; +;; ;; +;; See file COPYING for details ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;macro PutStr X +;{ +; local .__xyz1 +; local .__xyz2 +; push esi +; mov esi,.__xyz1 +; call sys_msg_board_str +; push eax +; mov eax,1 +; call delay_hs +; pop eax +; jmp .__xyz2 +;.__xyz1: +; db X +; db 13,10,0 +;.__xyz2: +; pop esi +;} +PCNET32_PORT_AUI equ 0x00 +PCNET32_PORT_10BT equ 0x01 +PCNET32_PORT_GPSI equ 0x02 +PCNET32_PORT_MII equ 0x03 +PCNET32_PORT_PORTSEL equ 0x03 +PCNET32_PORT_ASEL equ 0x04 +PCNET32_PORT_100 equ 0x40 +PCNET32_PORT_FD equ 0x80 +PCNET32_DMA_MASK equ 0xffffffff +PCNET32_LOG_TX_BUFFERS equ 1 +PCNET32_LOG_RX_BUFFERS equ 2 +PCNET32_TX_RING_SIZE equ (1 shl PCNET32_LOG_TX_BUFFERS) +PCNET32_TX_RING_MOD_MASK equ (PCNET32_TX_RING_SIZE-1) +PCNET32_TX_RING_LEN_BITS equ 0 +PCNET32_RX_RING_SIZE equ (1 shl PCNET32_LOG_RX_BUFFERS) +PCNET32_RX_RING_MOD_MASK equ (PCNET32_RX_RING_SIZE-1) +PCNET32_RX_RING_LEN_BITS equ (PCNET32_LOG_RX_BUFFERS shl 4) +PCNET32_PKT_BUF_SZ equ 1544 +PCNET32_PKT_BUF_SZ_NEG equ 0xf9f8 +pcnet32_txb equ (eth_data_start) +pcnet32_rxb equ ((pcnet32_txb+(PCNET32_PKT_BUF_SZ*PCNET32_TX_RING_SIZE)+0xf) and 0xfffffff0) +pcnet32_tx_ring equ ((pcnet32_rxb+(PCNET32_PKT_BUF_SZ*PCNET32_RX_RING_SIZE)+0xf) and 0xfffffff0) +pcnet32_rx_ring equ ((pcnet32_tx_ring+(16*PCNET32_TX_RING_SIZE)+0xf) and 0xfffffff0) +virtual at ((pcnet32_rx_ring+(16*PCNET32_RX_RING_SIZE)+0xf) and 0xfffffff0) +pcnet32_private: +.mode dw ? +.tlen_rlen dw ? +.phys_addr db ?,?,?,?,?,? +.reserved dw ? +.filter dd ?,? +.rx_ring dd ? +.tx_ring dd ? +.cur_rx dd ? +.cur_tx dd ? +.dirty_rx dd ? +.dirty_tx dd ? +.tx_full db ? +.options dd ? +.full_duplex db ? +.chip_version dd ? +.mii db ? +.ltint db ? +.dxsuflo db ? +.fset db ? +.fdx db ? +end virtual +virtual at 0 +pcnet32_rx_head: +.base dd ? +.buf_length dw ? +.status dw ? +.msg_length dd ? +.reserved dd ? +end virtual +virtual at 0 +pcnet32_tx_head: +.base dd ? +.length dw ? +.status dw ? +.misc dd ? +.reserved dd ? +end virtual + +uglobal +pcnet32_access: +.read_csr dd ? +.write_csr dd ? +.read_bcr dd ? +.write_bcr dd ? +.read_rap dd ? +.write_rap dd ? +.reset dd ? +endg + +iglobal +pcnet32_options_mapping: +dd PCNET32_PORT_ASEL ; 0 Auto-select +dd PCNET32_PORT_AUI ; 1 BNC/AUI +dd PCNET32_PORT_AUI ; 2 AUI/BNC +dd PCNET32_PORT_ASEL ; 3 not supported +dd PCNET32_PORT_10BT or PCNET32_PORT_FD ; 4 10baseT-FD +dd PCNET32_PORT_ASEL ; 5 not supported +dd PCNET32_PORT_ASEL ; 6 not supported +dd PCNET32_PORT_ASEL ; 7 not supported +dd PCNET32_PORT_ASEL ; 8 not supported +dd PCNET32_PORT_MII ; 9 MII 10baseT +dd PCNET32_PORT_MII or PCNET32_PORT_FD ; 10 MII 10baseT-FD +dd PCNET32_PORT_MII ; 11 MII (autosel) +dd PCNET32_PORT_10BT ; 12 10BaseT +dd PCNET32_PORT_MII or PCNET32_PORT_100 ; 13 MII 100BaseTx +dd PCNET32_PORT_MII or PCNET32_PORT_100 or PCNET32_PORT_FD ; 14 MII 100BaseTx-FD +dd PCNET32_PORT_ASEL ; 15 not supported +endg + +PCNET32_WIO_RDP equ 0x10 +PCNET32_WIO_RAP equ 0x12 +PCNET32_WIO_RESET equ 0x14 +PCNET32_WIO_BDP equ 0x16 +PCNET32_DWIO_RDP equ 0x10 +PCNET32_DWIO_RAP equ 0x14 +PCNET32_DWIO_RESET equ 0x18 +PCNET32_DWIO_BDP equ 0x1C +PCNET32_TOTAL_SIZE equ 0x20 +; ebx - index +; return: +; eax - data +pcnet32_wio_read_csr: + push edx + lea edx,[ebp+PCNET32_WIO_RAP] + mov ax,bx + out dx,ax + lea edx,[ebp+PCNET32_WIO_RDP] + in ax,dx + and eax,0xffff + pop edx + ret +; eax - data +; ebx - index +pcnet32_wio_write_csr: + push edx + lea edx,[ebp+PCNET32_WIO_RAP] + xchg eax,ebx + out dx,ax + xchg eax,ebx + lea edx,[ebp+PCNET32_WIO_RDP] + out dx,ax + pop edx + ret +; ebx - index +; return: +; eax - data +pcnet32_wio_read_bcr: + push edx + lea edx,[ebp+PCNET32_WIO_RAP] + mov ax,bx + out dx,ax + lea edx,[ebp+PCNET32_WIO_BDP] + in ax,dx + and eax,0xffff + pop edx + ret +; eax - data +; ebx - index +pcnet32_wio_write_bcr: + push edx + lea edx,[ebp+PCNET32_WIO_RAP] + xchg eax,ebx + out dx,ax + xchg eax,ebx + lea edx,[ebp+PCNET32_WIO_BDP] + out dx,ax + pop edx + ret +pcnet32_wio_read_rap: + push edx + lea edx,[ebp+PCNET32_WIO_RAP] + in ax,dx + and eax,0xffff + pop edx + ret +; eax - val +pcnet32_wio_write_rap: + push edx + lea edx,[ebp+PCNET32_WIO_RAP] + out dx,ax + pop edx + ret +pcnet32_wio_reset: + push edx + push eax + lea edx,[ebp+PCNET32_WIO_RESET] + in ax,dx + pop eax + pop edx + ret +pcnet32_wio_check: + push edx + mov ax,88 + lea edx,[ebp+PCNET32_WIO_RAP] + out dx,ax + nop + nop + in ax,dx + cmp ax,88 + sete al + pop edx + ret + +iglobal +pcnet32_wio: + dd pcnet32_wio_read_csr + dd pcnet32_wio_write_csr + dd pcnet32_wio_read_bcr + dd pcnet32_wio_write_bcr + dd pcnet32_wio_read_rap + dd pcnet32_wio_write_rap + dd pcnet32_wio_reset +endg + +; ebx - index +; return: +; eax - data +pcnet32_dwio_read_csr: + push edx + lea edx,[ebp+PCNET32_DWIO_RAP] + mov ebx,eax + out dx,eax + lea edx,[ebp+PCNET32_DWIO_RDP] + in eax,dx + and eax,0xffff + pop edx + ret +; ebx - index +; eax - data +pcnet32_dwio_write_csr: + push edx + lea edx,[ebp+PCNET32_DWIO_RAP] + xchg eax,ebx + out dx,eax + lea edx,[ebp+PCNET32_DWIO_RDP] + xchg eax,ebx + out dx,eax + pop edx + ret +; ebx - index +; return: +; eax - data +pcnet32_dwio_read_bcr: + push edx + lea edx,[ebp+PCNET32_DWIO_RAP] + mov ebx,eax + out dx,eax + lea edx,[ebp+PCNET32_DWIO_BDP] + in eax,dx + and eax,0xffff + pop edx + ret +; ebx - index +; eax - data +pcnet32_dwio_write_bcr: + push edx + lea edx,[ebp+PCNET32_DWIO_RAP] + xchg eax,ebx + out dx,eax + lea edx,[ebp+PCNET32_DWIO_BDP] + xchg eax,ebx + out dx,eax + pop edx + ret +pcnet32_dwio_read_rap: + push edx + lea edx,[ebp+PCNET32_DWIO_RAP] + in eax,dx + and eax,0xffff + pop edx + ret +; eax - val +pcnet32_dwio_write_rap: + push edx + lea edx,[ebp+PCNET32_DWIO_RAP] + out dx,eax + pop edx + ret +pcnet32_dwio_reset: + push edx + push eax + lea edx,[ebp+PCNET32_DWIO_RESET] + in eax,dx + pop eax + pop edx + ret +pcnet32_dwio_check: + push edx + lea edx,[PCNET32_DWIO_RAP] + mov eax,88 + out dx,eax + nop + nop + in eax,dx + and eax,0xffff + cmp eax,88 + sete al + pop edx + ret + +iglobal +pcnet32_dwio: + dd pcnet32_dwio_read_csr + dd pcnet32_dwio_write_csr + dd pcnet32_dwio_read_bcr + dd pcnet32_dwio_write_bcr + dd pcnet32_dwio_read_rap + dd pcnet32_dwio_write_rap + dd pcnet32_dwio_reset +endg + +pcnet32_init_ring: + mov [pcnet32_private.tx_full],0 + mov [pcnet32_private.cur_rx],0 + mov [pcnet32_private.cur_tx],0 + mov [pcnet32_private.dirty_rx],0 + mov [pcnet32_private.dirty_tx],0 + mov edi,pcnet32_rx_ring + mov ecx,PCNET32_RX_RING_SIZE + mov ebx,pcnet32_rxb +.rx_init: + mov [edi+pcnet32_rx_head.base],ebx + mov [edi+pcnet32_rx_head.buf_length],word PCNET32_PKT_BUF_SZ_NEG + mov [edi+pcnet32_rx_head.status],word 0x8000 + add ebx,PCNET32_PKT_BUF_SZ +; inc ebx + add edi,16 + loop .rx_init + mov edi,pcnet32_tx_ring + mov ecx,PCNET32_TX_RING_SIZE +.tx_init: + mov [edi+pcnet32_tx_head.base],dword 0 + mov [edi+pcnet32_tx_head.status],word 0 + add edi,16 + loop .tx_init + mov [pcnet32_private.tlen_rlen],(PCNET32_TX_RING_LEN_BITS or PCNET32_RX_RING_LEN_BITS) + mov esi,node_addr + mov edi,pcnet32_private.phys_addr + cld + movsd + movsw + mov dword [pcnet32_private.rx_ring],pcnet32_rx_ring + mov dword [pcnet32_private.tx_ring],pcnet32_tx_ring + ret +pcnet32_reset: + ; Reset PCNET32 + mov ebp,[io_addr] + call dword [pcnet32_access.reset] + ; set 32bit mode + mov ebx,20 + mov eax,2 + call dword [pcnet32_access.write_bcr] + ; set/reset autoselect bit + mov ebx,2 + call dword [pcnet32_access.read_bcr] + and eax,not 2 + test [pcnet32_private.options],PCNET32_PORT_ASEL + jz .L1 + or eax,2 +.L1: + call dword [pcnet32_access.write_bcr] + ; Handle full duplex setting + cmp byte [pcnet32_private.full_duplex],0 + je .L2 + mov ebx,9 + call dword [pcnet32_access.read_bcr] + and eax,not 3 + test [pcnet32_private.options],PCNET32_PORT_FD + jz .L3 + or eax,1 + cmp [pcnet32_private.options],PCNET32_PORT_FD or PCNET32_PORT_AUI + jne .L4 + or eax,2 + jmp .L4 +.L3: + test [pcnet32_private.options],PCNET32_PORT_ASEL + jz .L4 + cmp [pcnet32_private.chip_version],0x2627 + jne .L4 + or eax,3 +.L4: + mov ebx,9 + call dword [pcnet32_access.write_bcr] +.L2: + ; set/reset GPSI bit + mov ebx,124 + call dword [pcnet32_access.read_csr] + mov ecx,[pcnet32_private.options] + and ecx,PCNET32_PORT_PORTSEL + cmp ecx,PCNET32_PORT_GPSI + jne .L5 + or eax,0x10 +.L5: + call dword [pcnet32_access.write_csr] + cmp [pcnet32_private.mii],0 + je .L6 + test [pcnet32_private.options],PCNET32_PORT_ASEL + jnz .L6 + mov ebx,32 + call dword [pcnet32_access.read_bcr] + and eax,not 0x38 + test [pcnet32_private.options],PCNET32_PORT_FD + jz .L7 + or eax,0x10 +.L7: + test [pcnet32_private.options],PCNET32_PORT_100 + jz .L8 + or eax,0x08 +.L8: + call dword [pcnet32_access.write_bcr] + jmp .L9 +.L6: + test [pcnet32_private.options],PCNET32_PORT_ASEL + jz .L9 + mov ebx,32 +; PutStr "ASEL, enable auto-negotiation" + call dword [pcnet32_access.read_bcr] + and eax,not 0x98 + or eax,0x20 + call dword [pcnet32_access.write_bcr] +.L9: + cmp [pcnet32_private.ltint],0 + je .L10 + mov ebx,5 + call dword [pcnet32_access.read_csr] + or eax,(1 shl 14) + call dword [pcnet32_access.write_csr] +.L10: + mov eax,[pcnet32_private.options] + and eax,PCNET32_PORT_PORTSEL + shl eax,7 + mov [pcnet32_private.mode],ax + mov [pcnet32_private.filter],dword 0xffffffff + mov [pcnet32_private.filter+4],dword 0xffffffff + call pcnet32_init_ring + mov ebx,1 + mov eax,pcnet32_private + and eax,0xffff + call dword [pcnet32_access.write_csr] + mov eax,pcnet32_private + mov ebx,2 + shr eax,16 + call dword [pcnet32_access.write_csr] + mov ebx,4 + mov eax,0x0915 + call dword [pcnet32_access.write_csr] + mov ebx,0 + mov eax,1 + call dword [pcnet32_access.write_csr] + mov ecx,100 +.L11: + xor ebx,ebx + call dword [pcnet32_access.read_csr] + test ax,0x100 + jnz .L12 + loop .L11 +.L12: +; PutStr "hardware reset" + xor ebx,ebx + mov eax,0x0002 + call dword [pcnet32_access.write_csr] + xor ebx,ebx + call dword [pcnet32_access.read_csr] +; PutStr "PCNET reset complete" + ret +pcnet32_adjust_pci_device: + ;*******Get current setting************************ + mov al, 2 ;read a word + mov bh, [pci_dev] + mov ah, [pci_bus] + mov bl, 0x04 ;from command Register + call pci_read_reg + ;******see if its already set as bus master******** + mov bx, ax + and bx,5 + cmp bx,5 + je pcnet32_adjust_pci_device_Latency + ;******Make card a bus master******* + mov cx, ax ;value to write + mov bh, [pci_dev] + mov al, 2 ;write a word + or cx,5 + mov ah, [pci_bus] + mov bl, 0x04 ;to command register + call pci_write_reg + ;******Check latency setting*********** +pcnet32_adjust_pci_device_Latency: + ;*******Get current latency setting************************ +; mov al, 1 ;read a byte +; mov bh, [pci_dev] +; mov ah, [pci_bus] +; mov bl, 0x0D ;from Lantency Timer Register +; call pci_read_reg + ;******see if its aat least 64 clocks******** +; cmp ax,64 +; jge pcnet32_adjust_pci_device_Done + ;******Set latency to 32 clocks******* +; mov cx, 64 ;value to write +; mov bh, [pci_dev] +; mov al, 1 ;write a byte +; mov ah, [pci_bus] +; mov bl, 0x0D ;to Lantency Timer Register +; call pci_write_reg + ;******Check latency setting*********** +pcnet32_adjust_pci_device_Done: + ret +pcnet32_probe: + mov ebp,[io_addr] + call pcnet32_wio_reset + xor ebx,ebx + call pcnet32_wio_read_csr + cmp eax,4 + jne .try_dwio + call pcnet32_wio_check + and al,al + jz .try_dwio +; PutStr "Using WIO" + mov esi,pcnet32_wio + jmp .L1 +.try_dwio: + call pcnet32_dwio_reset + xor ebx,ebx + call pcnet32_dwio_read_csr + cmp eax,4 + jne .no_dev + call pcnet32_dwio_check + and al,al + jz .no_dev +; PutStr "Using DWIO" + mov esi,pcnet32_dwio + jmp .L1 +.no_dev: +; PutStr "PCNET32 not found" + ret +.L1: + mov edi,pcnet32_access + mov ecx,7 + cld + rep movsd + mov ebx,88 + call dword [pcnet32_access.read_csr] + mov ecx,eax + mov ebx,89 + call dword [pcnet32_access.read_csr] + shl eax,16 + or eax,ecx + mov ecx,eax + and ecx,0xfff + cmp ecx,3 + jne .no_dev + shr eax,12 + and eax,0xffff + mov [pcnet32_private.chip_version],eax +; PutStr "PCNET32 chip version OK" + mov [pcnet32_private.fdx],0 + mov [pcnet32_private.mii],0 + mov [pcnet32_private.fset],0 + mov [pcnet32_private.dxsuflo],0 + mov [pcnet32_private.ltint],0 + mov eax,[pcnet32_private.chip_version] + cmp eax,0x2420 + je .L2 + cmp eax,0x2430 + je .L3 + cmp eax,0x2621 + je .L4 + cmp eax,0x2623 + je .L5 + cmp eax,0x2624 + je .L6 + cmp eax,0x2625 + je .L7 + cmp eax,0x2626 + je .L8 + cmp eax,0x2627 + je .L9 +; PutStr "Invalid chip rev" + jmp .no_dev +.L2: +; PutStr "PCnet/PCI 79C970" + jmp .L10 +.L3: +; PutStr "PCnet/PCI 79C970" + jmp .L10 +.L4: +; PutStr "PCnet/PCI II 79C970A" + mov [pcnet32_private.fdx],1 + jmp .L10 +.L5: +; PutStr "PCnet/FAST 79C971" + mov [pcnet32_private.fdx],1 + mov [pcnet32_private.mii],1 + mov [pcnet32_private.fset],1 + mov [pcnet32_private.ltint],1 + jmp .L10 +.L6: +; PutStr "PCnet/FAST+ 79C972" + mov [pcnet32_private.fdx],1 + mov [pcnet32_private.mii],1 + mov [pcnet32_private.fset],1 + jmp .L10 +.L7: +; PutStr "PCnet/FAST III 79C973" + mov [pcnet32_private.fdx],1 + mov [pcnet32_private.mii],1 + jmp .L10 +.L8: +; PutStr "PCnet/Home 79C978" + mov [pcnet32_private.fdx],1 + mov ebx,49 + call dword [pcnet32_access.read_bcr] + call dword [pcnet32_access.write_bcr] + jmp .L10 +.L9: +; PutStr "PCnet/FAST III 79C975" + mov [pcnet32_private.fdx],1 + mov [pcnet32_private.mii],1 +.L10: + cmp [pcnet32_private.fset],1 + jne .L11 + mov ebx,18 + call dword [pcnet32_access.read_bcr] + or eax,0x800 + call dword [pcnet32_access.write_bcr] + mov ebx,80 + call dword [pcnet32_access.read_csr] + and eax,0xc00 + or eax,0xc00 + call dword [pcnet32_access.write_csr] + mov [pcnet32_private.dxsuflo],1 + mov [pcnet32_private.ltint],1 +.L11: + ; read MAC + mov edi,node_addr + mov edx,ebp + mov ecx,6 +.Lmac: + in al,dx + stosb + inc edx + loop .Lmac +; PutStr "MAC read" + call pcnet32_adjust_pci_device +; PutStr "PCI done" + mov eax,PCNET32_PORT_ASEL + mov [pcnet32_private.options],eax + mov [pcnet32_private.mode],word 0x0003 + mov [pcnet32_private.tlen_rlen],word (PCNET32_TX_RING_LEN_BITS or PCNET32_RX_RING_LEN_BITS) + mov esi,node_addr + mov edi,pcnet32_private.phys_addr + cld + movsd + movsw + mov [pcnet32_private.filter],dword 0 + mov [pcnet32_private.filter+4],dword 0 + mov dword [pcnet32_private.rx_ring],pcnet32_rx_ring + mov dword [pcnet32_private.tx_ring],pcnet32_tx_ring +; PutStr "Switching to 32" + mov ebx,20 + mov eax,2 + call dword [pcnet32_access.write_bcr] + mov ebx,1 + mov eax,(pcnet32_private and 0xffff) + call dword [pcnet32_access.write_csr] + mov ebx,2 + mov eax,(pcnet32_private shr 16) and 0xffff + call dword [pcnet32_access.write_csr] + mov ebx,0 + mov eax,1 + call dword [pcnet32_access.write_csr] + mov esi,1 + call delay_ms + call pcnet32_reset + mov eax, [pci_data] + mov [eth_status], eax + ret +pcnet32_poll: + xor eax,eax + mov [eth_rx_data_len],ax + mov eax,[pcnet32_private.cur_rx] + and eax,PCNET32_RX_RING_MOD_MASK + mov ebx,eax + imul esi,eax,PCNET32_PKT_BUF_SZ + add esi,pcnet32_rxb + shl ebx,4 + add ebx,pcnet32_rx_ring + mov cx,[ebx+pcnet32_rx_head.status] + test cx,0x8000 + jnz .L1 + cmp ch,3 + jne .L1 +; PutStr "PCNETRX" + mov ecx,[ebx+pcnet32_rx_head.msg_length] + and ecx,0xfff + sub ecx,4 + mov [eth_rx_data_len],cx + push ecx + shr ecx,2 + mov edi,Ether_buffer + cld + rep movsd + pop ecx + and ecx,3 + rep movsb + mov [ebx+pcnet32_rx_head.buf_length],word PCNET32_PKT_BUF_SZ_NEG + or [ebx+pcnet32_rx_head.status],word 0x8000 + inc [pcnet32_private.cur_rx] +.L1: + ret +; Pointer to 48 bit destination address in edi +; Type of packet in bx +; size of packet in ecx +; pointer to packet data in esi +pcnet32_xmit: + push edi + push esi + push ebx + push ecx +; PutStr "PCNETTX" + mov esi,edi + mov edi,[pcnet32_private.cur_tx] + imul edi,PCNET32_PKT_BUF_SZ + add edi,pcnet32_txb ; edi=ptxb + mov eax,edi + cld ; copy MAC + movsd + movsw + mov esi,node_addr + cld + movsd + movsw + mov [edi],bx + add edi,2 + mov esi,[esp+8] + mov ecx,[esp] + push ecx + shr ecx,2 + cld + rep movsd + pop ecx + and ecx,3 + rep movsb +; mov ecx,[esp] +; add ecx,14 ; ETH_HLEN +; xor eax,eax +; pad to min length (60=ETH_ZLEN) +; cmp ecx,60 +; jae .L1 +; sub ecx,60 +; cld +; rep stosb +;.L1: + mov edi,pcnet32_tx_ring+0 ; entry=0 + mov ecx,[esp] + add ecx,14 + cmp cx,60 + jae .L1 + mov cx,60 +.L1: + neg cx + mov [edi+pcnet32_tx_head.length],cx + mov [edi+pcnet32_tx_head.misc],dword 0 + mov [edi+pcnet32_tx_head.base],eax + mov [edi+pcnet32_tx_head.status],word 0x8300 + ; trigger an immediate send poll + mov ebx,0 + mov eax,0x0008 ; 0x0048 + mov ebp,[io_addr] + call dword [pcnet32_access.write_csr] + mov dword [pcnet32_private.cur_tx],0 + ; wait for TX to complete + mov ecx,[timer_ticks];[0xfdf0] + add ecx,100 +.L2: + mov ax,[edi+pcnet32_tx_head.status] + test ax,0x8000 + jz .L3 + cmp ecx,[timer_ticks];[0xfdf0] + jb .L4 + mov esi,10 + call delay_ms + jnz .L2 +.L4: +; PutStr "PCNET: Send timeout" +.L3: + mov dword [edi+pcnet32_tx_head.base],0 + pop ecx + pop ebx + pop esi + pop edi + ret diff --git a/kernel/trunk/network/eth_drv/drivers/rtl8029.inc b/kernel/trunk/network/eth_drv/drivers/rtl8029.inc new file mode 100644 index 0000000000..40683316b1 --- /dev/null +++ b/kernel/trunk/network/eth_drv/drivers/rtl8029.inc @@ -0,0 +1,955 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; RTL8029.INC ;; +;; ;; +;; Ethernet driver for Menuet OS ;; +;; ;; +;; Version 0.2 31 July 2002 ;; +;; ;; +;; This driver is based on the ns8390 driver from ;; +;; the etherboot 5.0.6 project. The copyright statement is ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;; remaining parts Copyright 2002 Mike Hibbett, ;; +;; mikeh@oceanfree.net ;; +;; ;; +;; See file COPYING for details ;; +;; ;; +;; While this implementation handles only PCI bus RTL8029 ;; +;; hardware, it can be easily adapted to other NE2000 clone ;; +;; products. I just dont have any to try! ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + + +;******************************************************************** +; Interface +; rtl8029_reset +; rtl8029_probe +; rtl8029_poll +; rtl8029_transmit +; +;******************************************************************** + + + + +;************************************************************************** +; 8390 Register Definitions +;************************************************************************** +D8390_P0_COMMAND equ 0x00 +D8390_P0_PSTART equ 0x01 +D8390_P0_PSTOP equ 0x02 +D8390_P0_BOUND equ 0x03 +D8390_P0_TSR equ 0x04 +D8390_P0_TPSR equ 0x04 +D8390_P0_TBCR0 equ 0x05 +D8390_P0_TBCR1 equ 0x06 +D8390_P0_ISR equ 0x07 +D8390_P0_RSAR0 equ 0x08 +D8390_P0_RSAR1 equ 0x09 +D8390_P0_RBCR0 equ 0x0A +D8390_P0_RBCR1 equ 0x0B +D8390_P0_RSR equ 0x0C +D8390_P0_RCR equ 0x0C +D8390_P0_TCR equ 0x0D +D8390_P0_DCR equ 0x0E +D8390_P0_IMR equ 0x0F +D8390_P1_COMMAND equ 0x00 +D8390_P1_PAR0 equ 0x01 +D8390_P1_PAR1 equ 0x02 +D8390_P1_PAR2 equ 0x03 +D8390_P1_PAR3 equ 0x04 +D8390_P1_PAR4 equ 0x05 +D8390_P1_PAR5 equ 0x06 +D8390_P1_CURR equ 0x07 +D8390_P1_MAR0 equ 0x08 + +D8390_COMMAND_PS0 equ 0x0 ; Page 0 select +D8390_COMMAND_PS1 equ 0x40 ; Page 1 select +D8390_COMMAND_PS2 equ 0x80 ; Page 2 select +D8390_COMMAND_RD2 equ 0x20 ; Remote DMA control +D8390_COMMAND_RD1 equ 0x10 +D8390_COMMAND_RD0 equ 0x08 +D8390_COMMAND_TXP equ 0x04 ; transmit packet +D8390_COMMAND_STA equ 0x02 ; start +D8390_COMMAND_STP equ 0x01 ; stop + +D8390_COMMAND_RD2_STA equ 0x22 +D8390_COMMAND_RD2_STP equ 0x21 +D8390_COMMAND_RD1_STA equ 0x12 +D8390_COMMAND_RD0_STA equ 0x0A +D8390_COMMAND_PS0_RD2_STP equ 0x21 +D8390_COMMAND_PS1_RD2_STP equ 0x61 +D8390_COMMAND_PS0_RD2_STA equ 0x22 +D8390_COMMAND_PS0_TXP_RD2_STA equ 0x26 + +D8390_RCR_MON equ 0x20 ; monitor mode + +D8390_DCR_FT1 equ 0x40 +D8390_DCR_LS equ 0x08 ; Loopback select +D8390_DCR_WTS equ 0x01 ; Word transfer select + +D8390_DCR_FT1_LS equ 0x48 +D8390_DCR_WTS_FT1_LS equ 0x49 + +D8390_ISR_PRX equ 0x01 ; successful recv +D8390_ISR_PTX equ 0x02 ; successful xmit +D8390_ISR_RXE equ 0x04 ; receive error +D8390_ISR_TXE equ 0x08 ; transmit error +D8390_ISR_OVW equ 0x10 ; Overflow +D8390_ISR_CNT equ 0x20 ; Counter overflow +D8390_ISR_RDC equ 0x40 ; Remote DMA complete +D8390_ISR_RST equ 0x80 ; reset + +D8390_RSTAT_PRX equ 0x01 ; successful recv +D8390_RSTAT_CRC equ 0x02 ; CRC error +D8390_RSTAT_FAE equ 0x04 ; Frame alignment error +D8390_RSTAT_OVER equ 0x08 ; FIFO overrun + +D8390_TXBUF_SIZE equ 6 +D8390_RXBUF_END equ 32 +D8390_PAGE_SIZE equ 256 + +ETH_ALEN equ 6 +ETH_HLEN equ 14 +ETH_ZLEN equ 60 +ETH_FRAME_LEN equ 1514 + +FLAG_PIO equ 0x01 +FLAG_16BIT equ 0x02 +ASIC_PIO equ 0 + +VENDOR_NONE equ 0 +VENDOR_WD equ 1 +VENDOR_NOVELL equ 2 +VENDOR_3COM equ 3 + +NE_ASIC_OFFSET equ 0x10 +NE_RESET equ 0x0F ; Used to reset card +NE_DATA equ 0x00 ; Used to read/write NIC mem + +MEM_8192 equ 32 +MEM_16384 equ 64 +MEM_32768 equ 128 + +ISA_MAX_ADDR equ 0x400 + +uglobal +eth_flags: db 0 +eth_vendor: db 0 +eth_nic_base: dw 0 +eth_asic_base: dw 0 +eth_memsize: db 0 +eth_rx_start: db 0 +eth_tx_start: db 0 +eth_bmem: dd 0 +eth_rmem: dd 0 +romdata: db 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +endg + +iglobal +test_data: db 'NE*000 memory',0 +test_buffer: db ' ',0 +endg + +uglobal +eth_type: dw 0 +pkthdr: db 0,0,0,0 ; status, next, (short) len +pktoff: dw 0 +eth_rx_data_ptr: dd 0 +eth_tmp_len: dw 0 +endg + + + +;*************************************************************************** +; Function +; eth_pio_read +; +; Description +; Read a frame from the ethernet card via Programmed I/O +; src in ebx +; cnt in ecx +; dst in edi +;*************************************************************************** +eth_pio_read: + mov al, [eth_flags] + and al, FLAG_16BIT + cmp al, 0 + je epr_001 + + inc ecx + and ecx, 0xFFFFFFFE + +epr_001: + mov al, D8390_COMMAND_RD2_STA + mov dx, [eth_nic_base] + add dx, D8390_P0_COMMAND + out dx, al + + mov al, cl + mov dx, [eth_nic_base] + add dx, D8390_P0_RBCR0 + out dx, al + + mov al, ch + mov dx, [eth_nic_base] + add dx, D8390_P0_RBCR1 + out dx, al + + mov al, bl + mov dx, [eth_nic_base] + add dx, D8390_P0_RSAR0 + out dx, al + + mov al, bh + mov dx, [eth_nic_base] + add dx, D8390_P0_RSAR1 + out dx, al + + mov al, D8390_COMMAND_RD0_STA + mov dx, [eth_nic_base] + add dx, D8390_P0_COMMAND + out dx, al + + mov dx, [eth_asic_base] + add dx, ASIC_PIO + + mov al, [eth_flags] + and al, FLAG_16BIT + cmp al, 0 + je epr_003 + + shr ecx, 1 + +epr_002: + ; 2 bytes at a time + in ax, dx + mov [edi], ax + add edi, 2 + loop epr_002 + ret + +epr_003: + ; 1 byte at a time + in al, dx + mov [edi], al + inc edi + loop epr_003 + ret + + + + +;*************************************************************************** +; Function +; eth_pio_write +; +; Description +; writes a frame to the ethernet card via Programmed I/O +; dst in ebx +; cnt in ecx +; src in esi +;*************************************************************************** +eth_pio_write: + mov al, [eth_flags] + and al, FLAG_16BIT + cmp al, 0 + je epw_001 + + inc ecx + and ecx, 0xFFFFFFFE + +epw_001: + mov al, D8390_COMMAND_RD2_STA + mov dx, [eth_nic_base] + add dx, D8390_P0_COMMAND + out dx, al + + mov al, D8390_ISR_RDC + mov dx, [eth_nic_base] + add dx, D8390_P0_ISR + out dx, al + + + mov al, cl + mov dx, [eth_nic_base] + add dx, D8390_P0_RBCR0 + out dx, al + + mov al, ch + mov dx, [eth_nic_base] + add dx, D8390_P0_RBCR1 + out dx, al + + mov al, bl + mov dx, [eth_nic_base] + add dx, D8390_P0_RSAR0 + out dx, al + + mov al, bh + mov dx, [eth_nic_base] + add dx, D8390_P0_RSAR1 + out dx, al + + mov al, D8390_COMMAND_RD1_STA + mov dx, [eth_nic_base] + add dx, D8390_P0_COMMAND + out dx, al + + mov dx, [eth_asic_base] + add dx, ASIC_PIO + + mov al, [eth_flags] + and al, FLAG_16BIT + cmp al, 0 + je epw_003 + + shr ecx, 1 + +epw_002: + ; 2 bytes at a time + mov ax, [esi] + add esi, 2 + out dx, ax + + loop epw_002 + jmp epw_004 + +epw_003: + ; 1 byte at a time + mov al, [esi] + inc esi + out dx, al + loop epw_003 + +epw_004: + mov dx, [eth_nic_base] + add dx, D8390_P0_ISR + +epw_005: + in al, dx + and al, D8390_ISR_RDC + cmp al, D8390_ISR_RDC + jne epw_005 + + ret + + + +;*************************************************************************** +; Function +; rtl8029_reset +; Description +; Place the chip (ie, the ethernet card) into a virgin state +; No inputs +; All registers destroyed +; +;*************************************************************************** +rtl8029_reset: + mov bx, [eth_nic_base] + + mov dx, bx + add dx, D8390_P0_COMMAND + mov al, D8390_COMMAND_PS0_RD2_STP + out dx, al + + mov dx, bx + add dx, D8390_P0_DCR + mov al, [eth_flags] + and al, FLAG_16BIT + cmp al, FLAG_16BIT + jne nsr_001 + + mov al, 0x49 + jmp nsr_002 + +nsr_001: + mov al, 0x48 + +nsr_002: + out dx, al + + xor al, al + + mov dx, bx + add dx, D8390_P0_RBCR0 + out dx, al + + mov dx, bx + add dx, D8390_P0_RBCR1 + out dx, al + + mov dx, bx + add dx, D8390_P0_RCR + mov al, 0x20 + out dx, al + + mov dx, bx + add dx, D8390_P0_TCR + mov al, 2 + out dx, al + + mov dx, bx + add dx, D8390_P0_TPSR + mov al, [eth_tx_start] + out dx, al + + mov dx, bx + add dx, D8390_P0_PSTART + mov al, [eth_rx_start] + out dx, al + + mov dx, bx + add dx, D8390_P0_PSTOP + mov al, [eth_memsize] + out dx, al + + mov dx, bx + add dx, D8390_P0_BOUND + mov al, [eth_memsize] + dec al + out dx, al + + mov dx, bx + add dx, D8390_P0_ISR + mov al, 0xff + out dx, al + + mov dx, bx + add dx, D8390_P0_IMR + xor al, al + out dx, al + + mov dx, bx + add dx, D8390_P0_COMMAND + mov al, D8390_COMMAND_PS1_RD2_STP + out dx, al + + mov dx, bx + add dx, D8390_P1_PAR0 + mov esi, node_addr + mov ecx, ETH_ALEN + +nsr_003: + mov al, [esi] + out dx, al + + inc esi + inc dx + loop nsr_003 + + mov dx, bx + add dx, D8390_P1_MAR0 + mov ecx, ETH_ALEN + + mov al, 0xff + +nsr_004: + out dx, al + inc dx + loop nsr_004 + + mov dx, bx + add dx, D8390_P1_CURR + mov al, [eth_rx_start] + out dx, al + + mov dx, bx + add dx, D8390_P0_COMMAND + mov al, D8390_COMMAND_PS0_RD2_STA + out dx, al + + mov dx, bx + add dx, D8390_P0_ISR + mov al, 0xff + out dx, al + + mov dx, bx + add dx, D8390_P0_TCR + mov al, 0 + out dx, al + + mov dx, bx + add dx, D8390_P0_RCR + mov al, 4 + out dx, al + + ret + + + +;*************************************************************************** +; Function +; rtl8029_probe +; Description +; Searches for an ethernet card, enables it and clears the rx buffer +; If a card was found, it enables the ethernet -> TCPIP link +; +;*************************************************************************** +rtl8029_probe: + mov eax, [io_addr] + mov [eth_nic_base], ax ; The IO address space is 16 bit only + + mov al, VENDOR_NONE + mov [eth_vendor], al + + mov al, [eth_vendor] + cmp al, VENDOR_NONE + + jne ep_check_have_vendor + xor eax, eax + mov [eth_bmem], eax + + mov al, FLAG_PIO + mov [eth_flags], al + + mov ax, [eth_nic_base] + add ax, NE_ASIC_OFFSET + mov [eth_asic_base], ax + + mov al, MEM_16384 + mov [eth_memsize], al + + mov al, 32 + mov [eth_tx_start], al + + add al, D8390_TXBUF_SIZE + mov [eth_rx_start], al + + mov dx, [eth_asic_base] + add dx, NE_RESET + + in al, dx + out dx, al + + in al, 0x84 + + mov bx, [eth_nic_base] + + mov dx, bx + add dx, D8390_P0_COMMAND + mov al, D8390_COMMAND_RD2_STP + out dx, al + + mov dx, bx + add dx, D8390_P0_RCR + mov al, D8390_RCR_MON + out dx, al + + mov dx, bx + add dx, D8390_P0_DCR + mov al, D8390_DCR_FT1_LS + out dx, al + + mov dx, bx + add dx, D8390_P0_PSTART + mov al, MEM_8192 + out dx, al + + mov dx, bx + add dx, D8390_P0_PSTOP + mov al, MEM_16384 + out dx, al + + mov esi, test_data + mov ebx, 8192 + mov ecx, 14 + call eth_pio_write + + mov ebx, 8192 + mov ecx, 14 + mov edi, test_buffer + call eth_pio_read + + mov esi, test_buffer + mov edi, test_data + mov ecx, 13 + cld + rep cmpsb + + je ep_set_vendor + + mov al, [eth_flags] + or al, FLAG_16BIT + mov [eth_flags], al + + mov al, MEM_32768 + mov [eth_memsize], al + + mov al, 64 + mov [eth_tx_start], al + + add al, D8390_TXBUF_SIZE + mov [eth_rx_start], al + + mov bx, [eth_nic_base] + + mov dx, bx + add dx, D8390_P0_DCR + mov al, D8390_DCR_WTS_FT1_LS + out dx, al + + mov dx, bx + add dx, D8390_P0_PSTART + mov al, MEM_16384 + out dx, al + + mov dx, bx + add dx, D8390_P0_PSTOP + mov al, MEM_32768 + out dx, al + + mov esi, test_data + mov ebx, 16384 + mov ecx, 14 + call eth_pio_write + + mov ebx, 16384 + mov ecx, 14 + mov edi, test_buffer + call eth_pio_read + + mov esi, test_buffer + mov edi, test_data + mov ecx, 13 + cld + rep cmpsb + +ep_set_vendor: + ; this bit is odd - probably left over from my hacking + mov ax, [eth_nic_base] + cmp ax, 0 + je rtl8029_exit + cmp ax, ISA_MAX_ADDR + jbe ep_001 + mov al, [eth_flags] + or al, FLAG_16BIT + mov [eth_flags], al + +ep_001: + mov al, VENDOR_NOVELL + mov [eth_vendor], al + + mov ebx, 0 + mov ecx, 16 + mov edi, romdata + call eth_pio_read + + + mov ecx, ETH_ALEN + mov esi, romdata + mov edi, node_addr + + mov bl, [eth_flags] + and bl, FLAG_16BIT + +ep_002: + mov al, [esi] + mov [edi], al + + inc edi + inc esi + cmp bl, FLAG_16BIT + jne ep_003 + + inc esi + +ep_003: + loop ep_002 + +ep_check_have_vendor: + mov al, [eth_vendor] + cmp al, VENDOR_NONE + je rtl8029_exit + + cmp al, VENDOR_3COM + je ep_reset_card + + mov eax, [eth_bmem] + mov [eth_rmem], eax + +ep_reset_card: + ; Reset the card + call rtl8029_reset + + ; Indicate that we have successfully reset the card + mov eax, [pci_data] + mov [eth_status], eax + +rtl8029_exit: + ret + + + +;*************************************************************************** +; Function +; rtl8029_poll +; +; Description +; Polls the ethernet card for a received packet +; Received data, if any, ends up in Ether_buffer +; +;*************************************************************************** +rtl8029_poll: + mov eax, Ether_buffer + mov [eth_rx_data_ptr], eax + + mov bx, [eth_nic_base] + + mov dx, bx + add dx, D8390_P0_RSR + in al, dx + + and al, D8390_RSTAT_PRX + cmp al, D8390_RSTAT_PRX + jne nsp_exit + + mov dx, bx + add dx, D8390_P0_BOUND + in al, dx + inc al + + cmp al, [eth_memsize] + jb nsp_001 + + mov al, [eth_rx_start] + +nsp_001: + mov ch, al + + mov dx, bx + add dx, D8390_P0_COMMAND + mov al, D8390_COMMAND_PS1 + out dx, al + + mov dx, bx + add dx, D8390_P1_CURR + in al, dx ; get current page + mov cl, al + + mov dx, bx + add dx, D8390_P0_COMMAND + mov al, D8390_COMMAND_PS0 + out dx, al + + cmp cl, [eth_memsize] + jb nsp_002 + + mov cl, [eth_rx_start] + +nsp_002: + cmp cl, ch + je nsp_exit + + xor ax, ax + mov ah, ch + + mov [pktoff], ax + + mov al, [eth_flags] + and al, FLAG_PIO + cmp al, FLAG_PIO + jne nsp_003 + + movzx ebx, word [pktoff] + mov edi, pkthdr + mov ecx, 4 + call eth_pio_read + jmp nsp_004 + +nsp_003: + mov edi, [eth_rmem] + movzx eax, word [pktoff] + add edi, eax + mov eax, [edi] + mov [pkthdr], eax + +nsp_004: + mov ax, [pktoff] + add ax, 4 + mov [pktoff], ax + + mov ax, [pkthdr + 2] + sub ax, 4 + + mov [eth_tmp_len], ax + + cmp ax, ETH_ZLEN + jb nsp_exit + + cmp ax, ETH_FRAME_LEN + ja nsp_exit + + mov al, [pkthdr] + and al, D8390_RSTAT_PRX + cmp al, D8390_RSTAT_PRX + jne nsp_exit + + ; Right, we can now get the data + + mov ax, [eth_tmp_len] + mov [eth_rx_data_len], ax + + xor ebx, ebx + mov bh, [eth_memsize] + sub bx, [pktoff] + + cmp [eth_tmp_len], bx + jbe nsp_005 + + mov al, [eth_flags] + and al, FLAG_PIO + cmp al, FLAG_PIO + jne nsp_006 + + push ebx + mov ecx, ebx + xor ebx, ebx + mov bx, [pktoff] + mov edi, [eth_rx_data_ptr] + call eth_pio_read + pop ebx + jmp nsp_007 + +nsp_006: + ; Not implemented, as we are using PIO mode on this card + +nsp_007: + xor ax, ax + mov ah, [eth_rx_start] + mov [pktoff], ax + + mov eax, [eth_rx_data_ptr] + add eax, ebx + mov [eth_rx_data_ptr], eax + + mov ax, [eth_tmp_len] + sub ax, bx + mov [eth_tmp_len], ax + +nsp_005: + mov al, [eth_flags] + and al, FLAG_PIO + cmp al, FLAG_PIO + jne nsp_008 + + xor ebx, ebx + mov bx, [pktoff] + xor ecx, ecx + mov cx, [eth_tmp_len] + mov edi, [eth_rx_data_ptr] + call eth_pio_read + jmp nsp_009 + +nsp_008: + ; Not implemented, as we are using PIO mode on this card + +nsp_009: + mov al, [pkthdr+1] + cmp al, [eth_rx_start] + jne nsp_010 + + mov al, [eth_memsize] + +nsp_010: + mov dx, [eth_nic_base] + add dx, D8390_P0_BOUND + dec al + out dx, al + +nsp_exit: + ret + + + +;*************************************************************************** +; Function +; rtl8029_transmit +; +; Description +; Transmits a packet of data via the ethernet card +; Pointer to 48 bit destination address in edi +; Type of packet in bx +; size of packet in ecx +; pointer to packet data in esi +; +;*************************************************************************** +rtl8029_transmit: + mov [eth_type], bx + + pusha + + mov esi, edi + xor bx, bx + mov bh, [eth_tx_start] + mov ecx, ETH_ALEN + call eth_pio_write + + mov esi, node_addr + xor bx, bx + mov bh, [eth_tx_start] + add bx, ETH_ALEN + mov ecx, ETH_ALEN + call eth_pio_write + + mov esi, eth_type + xor bx, bx + mov bh, [eth_tx_start] + add bx, ETH_ALEN + add bx, ETH_ALEN + mov ecx, 2 + call eth_pio_write + + popa + + xor bx, bx + mov bh, [eth_tx_start] + add bx, ETH_HLEN + push ecx + call eth_pio_write + pop ecx + + add ecx, ETH_HLEN + cmp ecx, ETH_ZLEN + jae nst_001 + + mov ecx, ETH_ZLEN + +nst_001: + push ecx + + mov bx, [eth_nic_base] + + mov dx, bx + add dx, D8390_P0_COMMAND + mov al, D8390_COMMAND_PS0_RD2_STA + out dx, al + + mov dx, bx + add dx, D8390_P0_TPSR + mov al, [eth_tx_start] + out dx, al + + pop ecx + + mov dx, bx + add dx, D8390_P0_TBCR0 + mov al, cl + out dx, al + + mov dx, bx + add dx, D8390_P0_TBCR1 + mov al, ch + out dx, al + + mov dx, bx + add dx, D8390_P0_COMMAND + mov al, D8390_COMMAND_PS0_TXP_RD2_STA + out dx, al + + ret diff --git a/kernel/trunk/network/eth_drv/drivers/rtl8139.inc b/kernel/trunk/network/eth_drv/drivers/rtl8139.inc new file mode 100644 index 0000000000..d4e50b4225 --- /dev/null +++ b/kernel/trunk/network/eth_drv/drivers/rtl8139.inc @@ -0,0 +1,595 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; RTL8139.INC ;; +;; ;; +;; Ethernet driver for Menuet OS ;; +;; ;; +;; Version 0.2 11 August 2003 ;; +;; ;; +;; Driver for chips of RealTek 8139 family ;; +;; References: ;; +;; www.realtek.com.hw - data sheets ;; +;; rtl8139.c - linux driver ;; +;; 8139too.c - linux driver ;; +;; ethernet driver template by Mike Hibbett ;; +;; ;; +;; The copyright statement is ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;; Copyright 2003 Endre Kozma, ;; +;; endre.kozma@axelero.hu ;; +;; ;; +;; See file COPYING for details ;; +;; ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ETH_ALEN equ 6 + ETH_HLEN equ (2 * ETH_ALEN + 2) + ETH_ZLEN equ 60 ; 60 + 4bytes auto payload for + ; mininmum 64bytes frame length + + PCI_REG_COMMAND equ 0x04 ; command register + PCI_BIT_PIO equ 0 ; bit0: io space control + PCI_BIT_MMIO equ 1 ; bit1: memory space control + PCI_BIT_MASTER equ 2 ; bit2: device acts as a PCI master + + RTL8139_REG_MAR0 equ 0x08 ; multicast filter register 0 + RTL8139_REG_MAR4 equ 0x0c ; multicast filter register 4 + RTL8139_REG_TSD0 equ 0x10 ; transmit status of descriptor + RTL8139_REG_TSAD0 equ 0x20 ; transmit start address of descriptor + RTL8139_REG_RBSTART equ 0x30 ; RxBuffer start address + RTL8139_REG_COMMAND equ 0x37 ; command register + RTL8139_REG_CAPR equ 0x38 ; current address of packet read + RTL8139_REG_IMR equ 0x3c ; interrupt mask register + RTL8139_REG_ISR equ 0x3e ; interrupt status register + RTL8139_REG_TXCONFIG equ 0x40 ; transmit configuration register + RTL8139_REG_TXCONFIG_0 equ 0x40 ; transmit configuration register 0 + RTL8139_REG_TXCONFIG_1 equ 0x41 ; transmit configuration register 1 + RTL8139_REG_TXCONFIG_2 equ 0x42 ; transmit configuration register 2 + RTL8139_REG_TXCONFIG_3 equ 0x43 ; transmit configuration register 3 + RTL8139_REG_RXCONFIG equ 0x44 ; receive configuration register 0 + RTL8139_REG_RXCONFIG_0 equ 0x44 ; receive configuration register 0 + RTL8139_REG_RXCONFIG_1 equ 0x45 ; receive configuration register 1 + RTL8139_REG_RXCONFIG_2 equ 0x46 ; receive configuration register 2 + RTL8139_REG_RXCONFIG_3 equ 0x47 ; receive configuration register 3 + RTL8139_REG_MPC equ 0x4c ; missed packet counter + RTL8139_REG_9346CR equ 0x50 ; serial eeprom 93C46 command register + RTL8139_REG_CONFIG1 equ 0x52 ; configuration register 1 + RTL8139_REG_CONFIG4 equ 0x5a ; configuration register 4 + RTL8139_REG_HLTCLK equ 0x5b ; undocumented halt clock register + RTL8139_REG_BMCR equ 0x62 ; basic mode control register + RTL8139_REG_ANAR equ 0x66 ; auto negotiation advertisement register + +; 5.1 packet header + RTL8139_BIT_RUNT equ 4 ; total packet length < 64 bytes + RTL8139_BIT_LONG equ 3 ; total packet length > 4k + RTL8139_BIT_CRC equ 2 ; crc error occured + RTL8139_BIT_FAE equ 1 ; frame alignment error occured + RTL8139_BIT_ROK equ 0 ; received packet is ok +; 5.4 command register + RTL8139_BIT_RST equ 4 ; reset bit + RTL8139_BIT_RE equ 3 ; receiver enabled + RTL8139_BIT_TE equ 2 ; transmitter enabled + RTL8139_BIT_BUFE equ 0 ; rx buffer is empty, no packet stored +; 5.6 interrupt status register + RTL8139_BIT_ISR_TOK equ 2 ; transmit ok + RTL8139_BIT_ISR_RER equ 1 ; receive error interrupt + RTL8139_BIT_ISR_ROK equ 0 ; receive ok +; 5.7 transmit configyration register + RTL8139_BIT_TX_MXDMA equ 8 ; Max DMA burst size per Tx DMA burst + RTL8139_BIT_TXRR equ 4 ; Tx Retry count 16+(TXRR*16) +; 5.8 receive configuration register + RTL8139_BIT_RXFTH equ 13 ; Rx fifo threshold + RTL8139_BIT_RBLEN equ 11 ; Ring buffer length indicator + RTL8139_BIT_RX_MXDMA equ 8 ; Max DMA burst size per Rx DMA burst + RTL8139_BIT_NOWRAP equ 7 ; transfered data wrapping + RTL8139_BIT_9356SEL equ 6 ; eeprom selector 9346/9356 + RTL8139_BIT_AER equ 5 ; accept error packets + RTL8139_BIT_AR equ 4 ; accept runt packets + RTL8139_BIT_AB equ 3 ; accept broadcast packets + RTL8139_BIT_AM equ 2 ; accept multicast packets + RTL8139_BIT_APM equ 1 ; accept physical match packets + RTL8139_BIT_AAP equ 0 ; accept all packets +; 5.9 93C46/93C56 command register + RTL8139_BIT_93C46_EEM1 equ 7 ; RTL8139 eeprom operating mode1 + RTL8139_BIT_93C46_EEM0 equ 6 ; RTL8139 eeprom operating mode0 + RTL8139_BIT_93C46_EECS equ 3 ; chip select + RTL8139_BIT_93C46_EESK equ 2 ; serial data clock + RTL8139_BIT_93C46_EEDI equ 1 ; serial data input + RTL8139_BIT_93C46_EEDO equ 0 ; serial data output +; 5.11 configuration register 1 + RTL8139_BIT_LWACT equ 4 ; see RTL8139_REG_CONFIG1 + RTL8139_BIT_SLEEP equ 1 ; sleep bit at older chips + RTL8139_BIT_PWRDWN equ 0 ; power down bit at older chips + RTL8139_BIT_PMEn equ 0 ; power management enabled +; 5.14 configuration register 4 + RTL8139_BIT_LWPTN equ 2 ; see RTL8139_REG_CONFIG4 +; 6.2 transmit status register + RTL8139_BIT_ERTXTH equ 16 ; early TX threshold + RTL8139_BIT_TOK equ 15 ; transmit ok + RTL8139_BIT_OWN equ 13 ; tx DMA operation is completed +; 6.18 basic mode control register + RTL8139_BIT_ANE equ 12 ; auto negotiation enable +; 6.20 auto negotiation advertisement register + RTL8139_BIT_TXFD equ 8 ; 100base-T full duplex + RTL8139_BIT_TX equ 7 ; 100base-T + RTL8139_BIT_10FD equ 6 ; 10base-T full duplex + RTL8139_BIT_10 equ 5 ; 10base-T + RTL8139_BIT_SELECTOR equ 0 ; binary encoded selector CSMA/CD=00001 +; RX/TX buffer size + RTL8139_RBLEN equ 0 ; 0==8K 1==16k 2==32k 3==64k + RTL8139_RX_BUFFER_SIZE equ (8192 shl RTL8139_RBLEN) + MAX_ETH_FRAME_SIZE equ 1516 ; exactly 1514 wthout CRC + RTL8139_NUM_TX_DESC equ 4 + RTL8139_TX_BUFFER_SIZE equ (MAX_ETH_FRAME_SIZE * RTL8139_NUM_TX_DESC) + RTL8139_TXRR equ 8 ; total retries = 16+(TXRR*16) + RTL8139_TX_MXDMA equ 6 ; 0==16 1==32 2==64 3==128 + ; 4==256 5==512 6==1024 7==2048 + RTL8139_ERTXTH equ 8 ; in unit of 32 bytes e.g:(8*32)=256 + RTL8139_RX_MXDMA equ 7 ; 0==16 1==32 2==64 3==128 + ; 4==256 5==512 6==1024 7==unlimited + RTL8139_RXFTH equ 7 ; 0==16 1==32 2==64 3==128 + ; 4==256 5==512 6==1024 7==no threshold + RTL8139_RX_CONFIG equ ((RTL8139_RBLEN shl RTL8139_BIT_RBLEN) \ + or (RTL8139_RX_MXDMA shl RTL8139_BIT_RX_MXDMA) \ + or (1 shl RTL8139_BIT_NOWRAP) \ + or (RTL8139_RXFTH shl RTL8139_BIT_RXFTH) \ + or (1 shl RTL8139_BIT_AB) or (1 shl RTL8139_BIT_APM) \ + or (1 shl RTL8139_BIT_AER) or (1 shl RTL8139_BIT_AR) \ + or (1 shl RTL8139_BIT_AM)) + RTL8139_TX_TIMEOUT equ 30 ; 300 milliseconds timeout + + EE_93C46_REG_ETH_ID equ 7 ; MAC offset + EE_93C46_READ_CMD equ (6 shl 6) ; 110b + 6bit address + EE_93C56_READ_CMD equ (6 shl 8) ; 110b + 8bit address + EE_93C46_CMD_LENGTH equ 9 ; start bit + cmd + 6bit address + EE_93C56_CMD_LENGTH equ 11 ; start bit + cmd + 8bit ddress + + VER_RTL8139 equ 1100000b + VER_RTL8139A equ 1110000b +; VER_RTL8139AG equ 1110100b + VER_RTL8139B equ 1111000b + VER_RTL8130 equ VER_RTL8139B + VER_RTL8139C equ 1110100b + VER_RTL8100 equ 1111010b + VER_RTL8100B equ 1110101b + VER_RTL8139D equ VER_RTL8100B + VER_RTL8139CP equ 1110110b + VER_RTL8101 equ 1110111b + + IDX_RTL8139 equ 0 + IDX_RTL8139A equ 1 + IDX_RTL8139B equ 2 + IDX_RTL8139C equ 3 + IDX_RTL8100 equ 4 + IDX_RTL8139D equ 5 + IDX_RTL8139D equ 6 + IDX_RTL8101 equ 7 + + +; These two must be 4 byte aligned ( which they are ) +rtl8139_rx_buff equ eth_data_start +rtl8139_tx_buff equ rtl8139_rx_buff + (RTL8139_RX_BUFFER_SIZE + MAX_ETH_FRAME_SIZE) + +uglobal + align 4 +rtl8139_rx_buff_offset: dd 0 +curr_tx_desc: dd 0 +endg + +iglobal +hw_ver_array: db VER_RTL8139, VER_RTL8139A, VER_RTL8139B, VER_RTL8139C + db VER_RTL8100, VER_RTL8139D, VER_RTL8139CP, VER_RTL8101 +HW_VER_ARRAY_SIZE = $-hw_ver_array +endg + +uglobal +hw_ver_id: db 0 +endg + +;*************************************************************************** +; Function +; rtl8139_probe +; Description +; Searches for an ethernet card, enables it and clears the rx buffer +; If a card was found, it enables the ethernet -> TCPIP link +; Destroyed registers +; eax, ebx, ecx, edx +; +;*************************************************************************** +rtl8139_probe: +; enable the device + mov al, 2 + mov ah, [pci_bus] + mov bh, [pci_dev] + mov bl, PCI_REG_COMMAND + call pci_read_reg + mov cx, ax + or cl, (1 shl PCI_BIT_MASTER) or (1 shl PCI_BIT_PIO) + and cl, not (1 shl PCI_BIT_MMIO) + mov al, 2 + mov ah, [pci_bus] + mov bh, [pci_dev] + mov bl, PCI_REG_COMMAND + call pci_write_reg +; get chip version + mov edx, [io_addr] + add edx, RTL8139_REG_TXCONFIG_2 + in ax, dx + shr ah, 2 + shr ax, 6 + and al, 01111111b + mov ecx, HW_VER_ARRAY_SIZE-1 +.chip_ver_loop: + cmp al, [hw_ver_array+ecx] + je .chip_ver_found + dec ecx + jns .chip_ver_loop + xor cl, cl ; default RTL8139 +.chip_ver_found: + mov [hw_ver_id], cl +; wake up the chip + mov edx, [io_addr] + add edx, RTL8139_REG_HLTCLK + mov al, 'R' ; run the clock + out dx, al +; unlock config and BMCR registers + add edx, RTL8139_REG_9346CR - RTL8139_REG_HLTCLK + mov al, (1 shl RTL8139_BIT_93C46_EEM1) or (1 shl RTL8139_BIT_93C46_EEM0) + out dx, al +; enable power management + add edx, RTL8139_REG_CONFIG1 - RTL8139_REG_9346CR + in al, dx + cmp byte [hw_ver_id], IDX_RTL8139B + jl .old_chip +; set LWAKE pin to active high (default value). +; it is for Wake-On-LAN functionality of some motherboards. +; this signal is used to inform the motherboard to execute a wake-up process. +; only at newer chips. + or al, (1 shl RTL8139_BIT_PMEn) + and al, not (1 shl RTL8139_BIT_LWACT) + out dx, al + add edx, RTL8139_REG_CONFIG4 - RTL8139_REG_CONFIG1 + in al, dx + and al, not (1 shl RTL8139_BIT_LWPTN) + out dx, al + jmp .finish_wake_up +.old_chip: +; wake up older chips + and al, not ((1 shl RTL8139_BIT_SLEEP) or (1 shl RTL8139_BIT_PWRDWN)) + out dx, al +.finish_wake_up: +; lock config and BMCR registers + xor al, al + mov edx, [io_addr] + add edx, RTL8139_REG_9346CR + out dx, al +;*************************************************************************** +; Function +; rt8139_reset +; Description +; Place the chip (ie, the ethernet card) into a virgin state +; Destroyed registers +; eax, ebx, ecx, edx +; +;*************************************************************************** +rtl8139_reset: + mov edx, [io_addr] + add edx, RTL8139_REG_COMMAND + mov al, 1 shl RTL8139_BIT_RST + out dx, al + mov cx, 1000 ; wait no longer for the reset +.wait_for_reset: + in al, dx + test al, 1 shl RTL8139_BIT_RST + jz .reset_completed ; RST remains 1 during reset + dec cx + jns .wait_for_reset +.reset_completed: +; get MAC (hardware address) + mov ecx, 2 +.mac_read_loop: + lea eax, [EE_93C46_REG_ETH_ID+ecx] + push ecx + call rtl8139_read_eeprom + pop ecx + mov [node_addr+ecx*2], ax + dec ecx + jns .mac_read_loop +; unlock config and BMCR registers + mov edx, [io_addr] + add edx, RTL8139_REG_9346CR + mov al, (1 shl RTL8139_BIT_93C46_EEM1) or (1 shl RTL8139_BIT_93C46_EEM0) + out dx, al +; initialize multicast registers (no filtering) + mov eax, 0xffffffff + add edx, RTL8139_REG_MAR0 - RTL8139_REG_9346CR + out dx, eax + add edx, RTL8139_REG_MAR4 - RTL8139_REG_MAR0 + out dx, eax +; enable Rx/Tx + mov al, (1 shl RTL8139_BIT_RE) or (1 shl RTL8139_BIT_TE) + add edx, RTL8139_REG_COMMAND - RTL8139_REG_MAR4 + out dx, al +; 32k Rxbuffer, unlimited dma burst, no wrapping, no rx threshold +; accept broadcast packets, accept physical match packets + mov ax, RTL8139_RX_CONFIG + add edx, RTL8139_REG_RXCONFIG - RTL8139_REG_COMMAND + out dx, ax +; 1024 bytes DMA burst, total retries = 16 + 8 * 16 = 144 + mov ax, (RTL8139_TX_MXDMA shl RTL8139_BIT_TX_MXDMA) \ + or (RTL8139_TXRR shl RTL8139_BIT_TXRR) + add edx, RTL8139_REG_TXCONFIG - RTL8139_REG_RXCONFIG + out dx, ax +; enable auto negotiation + add edx, RTL8139_REG_BMCR - RTL8139_REG_TXCONFIG + in ax, dx + or ax, (1 shl RTL8139_BIT_ANE) + out dx, ax +; set auto negotiation advertisement + add edx, RTL8139_REG_ANAR - RTL8139_REG_BMCR + in ax, dx + or ax, (1 shl RTL8139_BIT_SELECTOR) or (1 shl RTL8139_BIT_10) \ + or (1 shl RTL8139_BIT_10FD) or (1 shl RTL8139_BIT_TX) \ + or (1 shl RTL8139_BIT_TXFD) + out dx, ax +; lock config and BMCR registers + xor eax, eax + add edx, RTL8139_REG_9346CR - RTL8139_REG_ANAR + out dx, al +; init RX/TX pointers + mov [rtl8139_rx_buff_offset], eax + mov [curr_tx_desc], eax +; clear missing packet counter + add edx, RTL8139_REG_MPC - RTL8139_REG_9346CR + out dx, eax +; disable all interrupts + add edx, RTL8139_REG_IMR - RTL8139_REG_MPC + out dx, ax +; set RxBuffer address, init RX buffer offset, init TX ring + mov eax, rtl8139_rx_buff + add edx, RTL8139_REG_RBSTART - RTL8139_REG_IMR + out dx, eax +; Indicate that we have successfully reset the card + mov eax, [pci_data] + mov [eth_status], eax + ret + +;*************************************************************************** +; Function +; rtl8139_read_eeprom +; Description +; reads eeprom type 93c46 and 93c56 +; Parameters +; al - word to be read (6bit in case of 93c46 and 8bit otherwise) +; Return value +; ax - word read in +; Destroyed register(s) +; eax, cx, ebx, edx +; +;*************************************************************************** +rtl8139_read_eeprom: + movzx ebx, al + mov edx, [io_addr] + add edx, RTL8139_REG_RXCONFIG + in al, dx + test al, (1 shl RTL8139_BIT_9356SEL) + jz .type_93c46 +; and bl, 01111111b ; don't care first bit + or bx, EE_93C56_READ_CMD ; it contains start bit + mov cx, EE_93C56_CMD_LENGTH-1 ; cmd_loop counter + jmp .read_eeprom +.type_93c46: + and bl, 00111111b + or bx, EE_93C46_READ_CMD ; it contains start bit + mov cx, EE_93C46_CMD_LENGTH-1 ; cmd_loop counter +.read_eeprom: + add edx, RTL8139_REG_9346CR - RTL8139_REG_RXCONFIG_0 +; mov al, (1 shl RTL8139_BIT_93C46_EEM1) +; out dx, al + mov al, (1 shl RTL8139_BIT_93C46_EEM1) \ + or (1 shl RTL8139_BIT_93C46_EECS) ; wake up the eeprom + out dx, al +.cmd_loop: + mov al, (1 shl RTL8139_BIT_93C46_EEM1) or (1 shl RTL8139_BIT_93C46_EECS) + bt bx, cx + jnc .zero_bit + or al, (1 shl RTL8139_BIT_93C46_EEDI) +.zero_bit: + out dx, al +; push eax +; in eax, dx ; eeprom delay +; pop eax + or al, (1 shl RTL8139_BIT_93C46_EESK) + out dx, al +; in eax, dx ; eeprom delay + dec cx + jns .cmd_loop +; in eax, dx ; eeprom delay + mov al, (1 shl RTL8139_BIT_93C46_EEM1) or (1 shl RTL8139_BIT_93C46_EECS) + out dx, al + mov cl, 0xf +.read_loop: + shl ebx, 1 + mov al, (1 shl RTL8139_BIT_93C46_EEM1) \ + or (1 shl RTL8139_BIT_93C46_EECS) \ + or (1 shl RTL8139_BIT_93C46_EESK) + out dx, al +; in eax, dx ; eeprom delay + in al, dx + and al, (1 shl RTL8139_BIT_93C46_EEDO) + jz .dont_set + inc ebx +.dont_set: + mov al, (1 shl RTL8139_BIT_93C46_EEM1) \ + or (1 shl RTL8139_BIT_93C46_EECS) + out dx, al +; in eax, dx ; eeprom delay + dec cl + jns .read_loop + xor al, al + out dx, al + mov ax, bx + ret + +;*************************************************************************** +; Function +; rtl8139_transmit +; Description +; Transmits a packet of data via the ethernet card +; Pointer to 48 bit destination address in edi +; Type of packet in bx +; size of packet in ecx +; pointer to packet data in esi +; Destroyed registers +; eax, edx, esi, edi +; ToDo +; for waiting of timeout the rtl8139 internal timer +; should be used +; +;*************************************************************************** +rtl8139_transmit: + cmp ecx, MAX_ETH_FRAME_SIZE + jg .finish ; packet is too long + push ecx +; check descriptor + mov ecx, [curr_tx_desc] + mov edx, [io_addr] + lea edx, [edx+ecx*4+RTL8139_REG_TSD0] + push edx ebx + in ax, dx + and ax, (1 shl RTL8139_BIT_TOK) or (1 shl RTL8139_BIT_OWN) + cmp ax, (1 shl RTL8139_BIT_TOK) or (1 shl RTL8139_BIT_OWN) + jz .send_packet + test ax, 0x1fff ; or no size given + jz .send_packet +; wait for timeout + mov ebx, RTL8139_TX_TIMEOUT + mov eax, 0x5 ; delay x/100 secs + int 0x40 + in ax, dx + and ax, (1 shl RTL8139_BIT_TOK) or (1 shl RTL8139_BIT_OWN) + cmp ax, (1 shl RTL8139_BIT_TOK) or (1 shl RTL8139_BIT_OWN) + jz .send_packet +; chip hung, reset it + call rtl8139_reset +; reset the card +.send_packet: +; calculate tx_buffer address + pop ebx + push esi + mov eax, MAX_ETH_FRAME_SIZE + mul dword [curr_tx_desc] + mov esi, edi + lea edi, [rtl8139_tx_buff+eax] + mov eax, edi + cld +; copy destination address + movsd + movsw +; copy source address + mov esi, node_addr + movsd + movsw +; copy packet type + mov [edi], bx + add edi, 2 +; copy the packet data + pop esi edx ecx + push ecx + shr ecx, 2 + rep movsd + pop ecx + push ecx + and ecx, 3 + rep movsb +; set address + add edx, RTL8139_REG_TSAD0 - RTL8139_REG_TSD0 + out dx, eax +; set size and early threshold + pop eax ; pick up the size + add eax, ETH_HLEN + cmp eax, ETH_ZLEN + jnc .no_pad + mov eax, ETH_ZLEN +.no_pad: + or eax, (RTL8139_ERTXTH shl RTL8139_BIT_ERTXTH) + add edx, RTL8139_REG_TSD0 - RTL8139_REG_TSAD0 + out dx, eax +; get next descriptor 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, ... + inc dword [curr_tx_desc] + and dword [curr_tx_desc], 3 +.finish: + ret + +;*************************************************************************** +; Function +; rtl8139_poll +; +; Description +; Polls the ethernet card for a received packet +; Received data, if any, ends up in Ether_buffer +; Destroyed register(s) +; eax, edx, ecx +; +;*************************************************************************** +rtl8139_poll: + mov word [eth_rx_data_len], 0 + mov edx, [io_addr] + add edx, RTL8139_REG_COMMAND + in al, dx + test al, (1 shl RTL8139_BIT_BUFE) + jnz .finish +; new packet received copy it from rx_buffer into Ether_buffer + mov eax, rtl8139_rx_buff + add eax, [rtl8139_rx_buff_offset] +; check if packet is ok + test byte [eax], (1 shl RTL8139_BIT_ROK) + jz .reset_rx +; packet is ok copy it into the Ether_buffer + movzx ecx, word [eax+2] ; packet length + sub ecx, 4 ; don't copy CRC + mov word [eth_rx_data_len], cx + push ecx + shr ecx, 2 ; first copy dword-wise + lea esi, [eax+4] ; don't copy the packet header + mov edi, Ether_buffer + cld + rep movsd ; copy the dwords + pop ecx + and ecx, 3 + rep movsb ; copy the rest bytes +; update rtl8139_rx_buff_offset + movzx eax, word [eax+2] ; packet length + add eax, [rtl8139_rx_buff_offset] + add eax, 4+3 ; packet header is 4 bytes long + dword alignment + and eax, not 3 ; dword alignment + cmp eax, RTL8139_RX_BUFFER_SIZE + jl .no_wrap + sub eax, RTL8139_RX_BUFFER_SIZE +.no_wrap: + mov [rtl8139_rx_buff_offset], eax +; update CAPR register + sub eax, 0x10 ; value 0x10 is a constant for CAPR + add edx, RTL8139_REG_CAPR - RTL8139_REG_COMMAND + out dx, ax +.finish: +; clear active interrupt sources + mov edx, [io_addr] + add edx, RTL8139_REG_ISR + in ax, dx + out dx, ax + ret +.reset_rx: + in al, dx ; read command register + push eax + and al, not (1 shl RTL8139_BIT_RE) + out dx, al + pop eax + out dx, al + add edx, RTL8139_REG_RXCONFIG - RTL8139_REG_COMMAND + mov ax, RTL8139_RX_CONFIG + out dx, ax + ret diff --git a/kernel/trunk/network/eth_drv/drivers/sis900.inc b/kernel/trunk/network/eth_drv/drivers/sis900.inc new file mode 100644 index 0000000000..af54313b9e --- /dev/null +++ b/kernel/trunk/network/eth_drv/drivers/sis900.inc @@ -0,0 +1,1148 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ;; +;; SIS900.INC ;; +;; ;; +;; Ethernet driver for Menuet OS ;; +;; ;; +;; Version 0.4 26 April 2004 ;; +;; ;; +;; This driver is based on the SIS900 driver from ;; +;; the etherboot 5.0.6 project. The copyright statement is ;; +;; ;; +;; GNU GENERAL PUBLIC LICENSE ;; +;; Version 2, June 1991 ;; +;; ;; +;; remaining parts Copyright 2004 Jason Delozier, ;; +;; cordata51@hotmail.com ;; +;; ;; +;; See file COPYING for details ;; +;; ;; +;; Updates: ;; +;; Revision Look up table and SIS635 Mac Address by Jarek Pelczar ;; +;; ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;******************************************************************** +; Interface +; SIS900_reset +; SIS900_probe +; SIS900_poll +; SIS900_transmit +; +;******************************************************************** +;******************************************************************** +; Comments: +; Known to work with the following SIS900 ethernet cards: +; - Device ID: 0x0900 Vendor ID: 0x1039 Revision: 0x91 +; - Device ID: 0x0900 Vendor ID: 0x1039 Revision: 0x90 +; +; If your card is not listed, try it and let me know if it +; functions properly and it will be aded to the list. If not +; we may be able to add support for it. +; +; How To Use: +; Add the following lines to Ethernet.inc in their appropriate locations +; +; include "Sis900.INC" +; dd 0x09001039, SIS900_probe, SIS900_reset, SIS900_poll, +; SIS900_transmit +; dd 0x70161039, SIS900_probe, SIS900_reset, SIS900_poll, +; SIS900_transmit ;untested +; +; ToDo: +; - Enable MII interface for reading speed +; and duplex settings. +; +; - Update Poll routine to support packet fragmentation. +; +; - Add additional support for other sis900 based cards +; +;******************************************************************** + +; comment the next line out if you don't want debug info printed +; on the debug board. This option adds a lot of bytes to the driver +; so it's worth to comment it out. +; SIS900_DEBUG equ 1 + + +;* buffers and descriptors +cur_rx db 0 +NUM_RX_DESC equ 4 ;* Number of RX descriptors * +NUM_TX_DESC equ 1 ;* Number of TX descriptors * +RX_BUFF_SZ equ 1520 ;* Buffer size for each Rx buffer * +TX_BUFF_SZ equ 1516 ;* Buffer size for each Tx buffer * + +uglobal +align 4 +txd: times (3 * NUM_TX_DESC) dd 0 +rxd: times (3 * NUM_RX_DESC) dd 0 +endg + +txb equ eth_data_start +rxb equ txb + (NUM_TX_DESC * TX_BUFF_SZ) +SIS900_ETH_ALEN equ 6 ;* Size of Ethernet address * +SIS900_ETH_HLEN equ 14 ;* Size of ethernet header * +SIS900_ETH_ZLEN equ 60 ;* Minimum packet length * +SIS900_DSIZE equ 0x00000fff +SIS900_CRC_SIZE equ 4 +SIS900_RFADDR_shift equ 16 +;SIS900 Symbolic offsets to registers. + SIS900_cr equ 0x0 ; Command Register + SIS900_cfg equ 0x4 ; Configuration Register + SIS900_mear equ 0x8 ; EEPROM Access Register + SIS900_ptscr equ 0xc ; PCI Test Control Register + SIS900_isr equ 0x10 ; Interrupt Status Register + SIS900_imr equ 0x14 ; Interrupt Mask Register + SIS900_ier equ 0x18 ; Interrupt Enable Register + SIS900_epar equ 0x18 ; Enhanced PHY Access Register + SIS900_txdp equ 0x20 ; Transmit Descriptor Pointer Register + SIS900_txcfg equ 0x24 ; Transmit Configuration Register + SIS900_rxdp equ 0x30 ; Receive Descriptor Pointer Register + SIS900_rxcfg equ 0x34 ; Receive Configuration Register + SIS900_flctrl equ 0x38 ; Flow Control Register + SIS900_rxlen equ 0x3c ; Receive Packet Length Register + SIS900_rfcr equ 0x48 ; Receive Filter Control Register + SIS900_rfdr equ 0x4C ; Receive Filter Data Register + SIS900_pmctrl equ 0xB0 ; Power Management Control Register + SIS900_pmer equ 0xB4 ; Power Management Wake-up Event Register +;SIS900 Command Register Bits + SIS900_RELOAD equ 0x00000400 + SIS900_ACCESSMODE equ 0x00000200 + SIS900_RESET equ 0x00000100 + SIS900_SWI equ 0x00000080 + SIS900_RxRESET equ 0x00000020 + SIS900_TxRESET equ 0x00000010 + SIS900_RxDIS equ 0x00000008 + SIS900_RxENA equ 0x00000004 + SIS900_TxDIS equ 0x00000002 + SIS900_TxENA equ 0x00000001 +;SIS900 Configuration Register Bits + SIS900_DESCRFMT equ 0x00000100 ; 7016 specific + SIS900_REQALG equ 0x00000080 + SIS900_SB equ 0x00000040 + SIS900_POW equ 0x00000020 + SIS900_EXD equ 0x00000010 + SIS900_PESEL equ 0x00000008 + SIS900_LPM equ 0x00000004 + SIS900_BEM equ 0x00000001 + SIS900_RND_CNT equ 0x00000400 + SIS900_FAIR_BACKOFF equ 0x00000200 + SIS900_EDB_MASTER_EN equ 0x00002000 +;SIS900 Eeprom Access Reigster Bits + SIS900_MDC equ 0x00000040 + SIS900_MDDIR equ 0x00000020 + SIS900_MDIO equ 0x00000010 ; 7016 specific + SIS900_EECS equ 0x00000008 + SIS900_EECLK equ 0x00000004 + SIS900_EEDO equ 0x00000002 + SIS900_EEDI equ 0x00000001 +;SIS900 TX Configuration Register Bits + SIS900_ATP equ 0x10000000 ;Automatic Transmit Padding + SIS900_MLB equ 0x20000000 ;Mac Loopback Enable + SIS900_HBI equ 0x40000000 ;HeartBeat Ignore (Req for full-dup) + SIS900_CSI equ 0x80000000 ;CarrierSenseIgnore (Req for full-du +;SIS900 RX Configuration Register Bits + SIS900_AJAB equ 0x08000000 ; + SIS900_ATX equ 0x10000000 ;Accept Transmit Packets + SIS900_ARP equ 0x40000000 ;accept runt packets (<64bytes) + SIS900_AEP equ 0x80000000 ;accept error packets +;SIS900 Interrupt Reigster Bits + SIS900_WKEVT equ 0x10000000 + SIS900_TxPAUSEEND equ 0x08000000 + SIS900_TxPAUSE equ 0x04000000 + SIS900_TxRCMP equ 0x02000000 + SIS900_RxRCMP equ 0x01000000 + SIS900_DPERR equ 0x00800000 + SIS900_SSERR equ 0x00400000 + SIS900_RMABT equ 0x00200000 + SIS900_RTABT equ 0x00100000 + SIS900_RxSOVR equ 0x00010000 + SIS900_HIBERR equ 0x00008000 + SIS900_SWINT equ 0x00001000 + SIS900_MIBINT equ 0x00000800 + SIS900_TxURN equ 0x00000400 + SIS900_TxIDLE equ 0x00000200 + SIS900_TxERR equ 0x00000100 + SIS900_TxDESC equ 0x00000080 + SIS900_TxOK equ 0x00000040 + SIS900_RxORN equ 0x00000020 + SIS900_RxIDLE equ 0x00000010 + SIS900_RxEARLY equ 0x00000008 + SIS900_RxERR equ 0x00000004 + SIS900_RxDESC equ 0x00000002 + SIS900_RxOK equ 0x00000001 +;SIS900 Interrupt Enable Reigster Bits + SIS900_IE equ 0x00000001 +;SIS900 Revision ID + SIS900B_900_REV equ 0x03 + SIS630A_900_REV equ 0x80 + SIS630E_900_REV equ 0x81 + SIS630S_900_REV equ 0x82 + SIS630EA1_900_REV equ 0x83 + SIS630ET_900_REV equ 0x84 + SIS635A_900_REV equ 0x90 + SIS900_960_REV equ 0x91 +;SIS900 Receive Filter Control Register Bits + SIS900_RFEN equ 0x80000000 + SIS900_RFAAB equ 0x40000000 + SIS900_RFAAM equ 0x20000000 + SIS900_RFAAP equ 0x10000000 + SIS900_RFPromiscuous equ 0x70000000 +;SIS900 Reveive Filter Data Mask + SIS900_RFDAT equ 0x0000FFFF +;SIS900 Eeprom Address + SIS900_EEPROMSignature equ 0x00 + SIS900_EEPROMVendorID equ 0x02 + SIS900_EEPROMDeviceID equ 0x03 + SIS900_EEPROMMACAddr equ 0x08 + SIS900_EEPROMChecksum equ 0x0b +;The EEPROM commands include the alway-set leading bit. +;SIS900 Eeprom Command + SIS900_EEread equ 0x0180 + SIS900_EEwrite equ 0x0140 + SIS900_EEerase equ 0x01C0 + SIS900_EEwriteEnable equ 0x0130 + SIS900_EEwriteDisable equ 0x0100 + SIS900_EEeraseAll equ 0x0120 + SIS900_EEwriteAll equ 0x0110 + SIS900_EEaddrMask equ 0x013F + SIS900_EEcmdShift equ 16 +;For SiS962 or SiS963, request the eeprom software access + SIS900_EEREQ equ 0x00000400 + SIS900_EEDONE equ 0x00000200 + SIS900_EEGNT equ 0x00000100 +;General Varibles + SIS900_pci_revision: db 0 + SIS900_Status dd 0x03000000 +sis900_specific_table: +; dd SIS630A_900_REV,Get_Mac_SIS630A_900_REV,0 +; dd SIS630E_900_REV,Get_Mac_SIS630E_900_REV,0 + dd SIS630S_900_REV,Get_Mac_SIS635_900_REV,0 + dd SIS630EA1_900_REV,Get_Mac_SIS635_900_REV,0 + dd SIS630ET_900_REV,Get_Mac_SIS635_900_REV,0;SIS630ET_900_REV_SpecialFN + dd SIS635A_900_REV,Get_Mac_SIS635_900_REV,0 + dd SIS900_960_REV,SIS960_get_mac_addr,0 + dd SIS900B_900_REV,SIS900_get_mac_addr,0 + dd 0,0,0,0 ; end of list +sis900_get_mac_func: dd 0 +sis900_special_func: dd 0 +sis900_table_entries: db 8 + +;*************************************************************************** +; Function +; SIS900_probe +; Description +; Searches for an ethernet card, enables it and clears the rx buffer +; If a card was found, it enables the ethernet -> TCPIP link +;not done - still need to probe mii transcievers +;*************************************************************************** +if defined SIS900_DEBUG +SIS900_Debug_Str_Unsupported db 'Sorry your card is unsupported ',13,10,0 +end if +SIS900_probe: +;******Wake Up Chip******* + mov al, 4 + mov bh, [pci_dev] + mov ecx, 0 + mov ah, [pci_bus] + mov bl, 0x40 + call pci_write_reg +;*******Set some PCI Settings********* + call SIS900_adjust_pci_device +;*****Get Card Revision****** + mov al, 1 ;one byte to read + mov bh, [pci_dev] + mov ah, [pci_bus] + mov bl, 0x08 ;Revision Register + call pci_read_reg + mov [SIS900_pci_revision], al ;save the revision for later use +;****** Look up through the sis900_specific_table + mov esi,sis900_specific_table +.probe_loop: + cmp dword [esi],0 ; Check if we reached end of the list + je .probe_loop_failed + cmp al,[esi] ; Check if revision is OK + je .probe_loop_ok + add esi,12 ; Advance to next entry + jmp .probe_loop +.probe_loop_failed: + jmp SIS900_Probe_Unsupported +;*********Find Get Mac Function********* +.probe_loop_ok: + mov eax,[esi+4] ; Get pointer to "get MAC" function + mov [sis900_get_mac_func],eax + mov eax,[esi+8] ; Get pointer to special initialization fn + mov [sis900_special_func],eax +;******** Get MAC ******** + call dword [sis900_get_mac_func] +;******** Call special initialization fn if requested ******** + cmp dword [sis900_special_func],0 + je .no_special_init + call dword [sis900_special_func] +.no_special_init: +;******** Set table entries ******** + mov al,[SIS900_pci_revision] + cmp al,SIS635A_900_REV + jae .ent16 + cmp al,SIS900B_900_REV + je .ent16 + jmp .ent8 +.ent16: + mov byte [sis900_table_entries],16 +.ent8: +;*******Probe for mii transceiver******* +;TODO!!********************* +;*******Initialize Device******* + call sis900_init + ret + +SIS900_Probe_Unsupported: +if defined SIS900_DEBUG + mov esi, SIS900_Debug_Str_Unsupported + call sys_msg_board_str +end if + ret +;*************************************************************************** +; Function: sis900_init +; +; Description: resets the ethernet controller chip and various +; data structures required for sending and receiving packets. +; +; Arguments: +; +; returns: none +;not done +;*************************************************************************** +sis900_init: + call SIS900_reset ;Done + call SIS900_init_rxfilter ;Done + call SIS900_init_txd ;Done + call SIS900_init_rxd ;Done + call SIS900_set_rx_mode ;done + call SIS900_set_tx_mode + ;call SIS900_check_mode + ret + +;*************************************************************************** +; Function +; SIS900_reset +; Description +; disables interrupts and soft resets the controller chip +; +;done+ +;*************************************************************************** +if defined SIS900_DEBUG + SIS900_Debug_Reset_Failed db 'Reset Failed ',0 +end if +SIS900_reset: + ;******Disable Interrupts and reset Receive Filter******* + mov ebp, [io_addr] ; base address + xor eax, eax ; 0 to initialize + lea edx,[ebp+SIS900_ier] + out dx, eax ; Write 0 to location + lea edx,[ebp+SIS900_imr] + out dx, eax ; Write 0 to location + lea edx,[ebp+SIS900_rfcr] + out dx, eax ; Write 0 to location + ;*******Reset Card*********************************************** + lea edx,[ebp+SIS900_cr] + in eax, dx ; Get current Command Register + or eax, SIS900_RESET ; set flags + or eax, SIS900_RxRESET ; + or eax, SIS900_TxRESET ; + out dx, eax ; Write new Command Register + ;*******Wait Loop************************************************ + lea edx,[ebp+SIS900_isr] + mov ecx, [SIS900_Status] ; Status we would like to see from card + mov ebx, 2001 ; only loop 1000 times +SIS900_Wait: + dec ebx ; 1 less loop + jz SIS900_DoneWait_e ; 1000 times yet? + in eax, dx ; move interrup status to eax + and eax, ecx + xor ecx, eax + jz SIS900_DoneWait + jmp SIS900_Wait +SIS900_DoneWait_e: +if defined SIS900_DEBUG + mov esi, SIS900_Debug_Reset_Failed + call sys_msg_board_str +end if +SIS900_DoneWait: + ;*******Set Configuration Register depending on Card Revision******** + lea edx,[ebp+SIS900_cfg] + mov eax, SIS900_PESEL ; Configuration Register Bit + mov bl, [SIS900_pci_revision] ; card revision + mov cl, SIS635A_900_REV ; Check card revision + cmp bl, cl + je SIS900_RevMatch + mov cl, SIS900B_900_REV ; Check card revision + cmp bl, cl + je SIS900_RevMatch + out dx, eax ; no revision match + jmp SIS900_Reset_Complete +SIS900_RevMatch: ; Revision match + or eax, SIS900_RND_CNT ; Configuration Register Bit + out dx, eax +SIS900_Reset_Complete: + mov eax, [pci_data] + mov [eth_status], eax + ret + +;*************************************************************************** +; Function: sis_init_rxfilter +; +; Description: sets receive filter address to our MAC address +; +; Arguments: +; +; returns: +;done+ +;*************************************************************************** +SIS900_init_rxfilter: + ;****Get Receive Filter Control Register ******** + mov ebp, [io_addr] ; base address + lea edx,[ebp+SIS900_rfcr] + in eax, dx ; get register + push eax + ;****disable packet filtering before setting filter******* + mov eax, SIS900_RFEN ;move receive filter enable flag + not eax ;1s complement + pop ebx ;and with our saved register + and eax, ebx ;disable receiver + push ebx ;save filter for another use + out dx, eax ;set receive disabled + ;********load MAC addr to filter data register********* + xor ecx, ecx +SIS900_RXINT_Mac_Write: + ;high word of eax tells card which mac byte to write + mov eax, ecx + lea edx,[ebp+SIS900_rfcr] + shl eax, 16 ; + out dx, eax ; + lea edx,[ebp+SIS900_rfdr] + mov ax, word [node_addr+ecx*2] ; Get Mac ID word + out dx, ax ; Send Mac ID + inc cl ; send next word + cmp cl, 3 ; more to send? + jne SIS900_RXINT_Mac_Write + ;********enable packet filitering ***** + pop eax ;old register value + lea edx,[ebp+SIS900_rfcr] + or eax, SIS900_RFEN ;enable filtering + out dx, eax ;set register + ret + +;*************************************************************************** +;* +;* Function: sis_init_txd +;* +;* Description: initializes the Tx descriptor +;* +;* Arguments: +;* +;* returns: +;*done +;*************************************************************************** +SIS900_init_txd: + ;********** initialize TX descriptor ************** + mov [txd], dword 0 ;put link to next descriptor in link field + mov [txd+4],dword 0 ;clear status field + mov [txd+8], dword txb ;save address to buffer ptr field + ;*************** load Transmit Descriptor Register *************** + mov dx, [io_addr] ; base address + add dx, SIS900_txdp ; TX Descriptor Pointer + mov eax, txd ; First Descriptor + out dx, eax ; move the pointer + ret + +;*************************************************************************** +;* Function: sis_init_rxd +;* +;* Description: initializes the Rx descriptor ring +;* +;* Arguments: +;* +;* Returns: +;*done +;*************************************************************************** +SIS900_init_rxd: + xor ecx,ecx + mov [cur_rx], cl ;Set cuurent rx discriptor to 0 + ;******** init RX descriptors ******** +SIS900_init_rxd_Loop: + mov eax, ecx ;current descriptor + imul eax, 12 ; + mov ebx, ecx ;determine next link descriptor + inc ebx ; + cmp ebx, NUM_RX_DESC ; + jne SIS900_init_rxd_Loop_0 ; + xor ebx, ebx ; +SIS900_init_rxd_Loop_0: ; + imul ebx, 12 ; + add ebx, rxd ; + mov [rxd+eax], ebx ;save link to next descriptor + mov [rxd+eax+4],dword RX_BUFF_SZ ;status bits init to buf size + mov ebx, ecx ;find where the buf is located + imul ebx,RX_BUFF_SZ ; + add ebx, rxb ; + mov [rxd+eax+8], ebx ;save buffer pointer + inc ecx ;next descriptor + cmp ecx, NUM_RX_DESC ; + jne SIS900_init_rxd_Loop ; + ;********* load Receive Descriptor Register with address of first + ; descriptor********* + mov dx, [io_addr] + add dx, SIS900_rxdp + mov eax, rxd + out dx, eax + ret + +;*************************************************************************** +;* Function: sis900_set_tx_mode +;* +;* Description: +;* sets the transmit mode to allow for full duplex +;* +;* +;* Arguments: +;* +;* Returns: +;* +;* Comments: +;* If you are having problems transmitting packet try changing the +;* Max DMA Burst, Possible settings are as follows: +;* 0x00000000 = 512 bytes +;* 0x00100000 = 4 bytes +;* 0x00200000 = 8 bytes +;* 0x00300000 = 16 bytes +;* 0x00400000 = 32 bytes +;* 0x00500000 = 64 bytes +;* 0x00600000 = 128 bytes +;* 0x00700000 = 256 bytes +;*************************************************************************** +SIS900_set_tx_mode: + mov ebp,[io_addr] + lea edx,[ebp+SIS900_cr] + in eax, dx ; Get current Command Register + or eax, SIS900_TxENA ;Enable Receive + out dx, eax + lea edx,[ebp+SIS900_txcfg]; Transmit config Register offset + mov eax, SIS900_ATP ;allow automatic padding + or eax, SIS900_HBI ;allow heartbeat ignore + or eax, SIS900_CSI ;allow carrier sense ignore + or eax, 0x00600000 ;Max DMA Burst + or eax, 0x00000100 ;TX Fill Threshold + or eax, 0x00000020 ;TX Drain Threshold + out dx, eax + ret + +;*************************************************************************** +;* Function: sis900_set_rx_mode +;* +;* Description: +;* sets the receive mode to accept all broadcast packets and packets +;* with our MAC address, and reject all multicast packets. Also allows +;* full-duplex +;* +;* Arguments: +;* +;* Returns: +;* +;* Comments: +;* If you are having problems receiving packet try changing the +;* Max DMA Burst, Possible settings are as follows: +;* 0x00000000 = 512 bytes +;* 0x00100000 = 4 bytes +;* 0x00200000 = 8 bytes +;* 0x00300000 = 16 bytes +;* 0x00400000 = 32 bytes +;* 0x00500000 = 64 bytes +;* 0x00600000 = 128 bytes +;* 0x00700000 = 256 bytes +;*************************************************************************** +SIS900_mc_filter: times 16 dw 0 +SIS900_set_rx_mode: + mov ebp,[io_addr] + ;**************update Multicast Hash Table in Receive Filter + mov ebx, 0xffff + xor cl, cl +SIS900_set_rx_mode_Loop: + mov eax, ecx + shl eax, 1 + mov [SIS900_mc_filter+eax], ebx + lea edx,[ebp+SIS900_rfcr] ; Receive Filter Control Reg offset + mov eax, 4 ;determine table entry + add al, cl + shl eax, 16 + out dx, eax ;tell card which entry to modify + lea edx,[ebp+SIS900_rfdr] ; Receive Filter Control Reg offset + mov eax, ebx ;entry value + out dx, ax ;write value to table in card + inc cl ;next entry + cmp cl,[sis900_table_entries] ; + jl SIS900_set_rx_mode_Loop + ;*******Set Receive Filter Control Register************* + lea edx,[ebp+SIS900_rfcr] ; Receive Filter Control Register offset + mov eax, SIS900_RFAAB ;accecpt all broadcast packets + or eax, SIS900_RFAAM ;accept all multicast packets + or eax, SIS900_RFAAP ;Accept all packets + or eax, SIS900_RFEN ;enable receiver filter + out dx, eax + ;******Enable Receiver************ + lea edx,[ebp+SIS900_cr] ; Command Register offset + in eax, dx ; Get current Command Register + or eax, SIS900_RxENA ;Enable Receive + out dx, eax + ;*********Set + lea edx,[ebp+SIS900_rxcfg] ; Receive Config Register offset + mov eax, SIS900_ATX ;Accept Transmit Packets + ; (Req for full-duplex and PMD Loopback) + or eax, 0x00600000 ;Max DMA Burst + or eax, 0x00000002 ;RX Drain Threshold, 8X8 bytes or 64bytes + out dx, eax ; + ret + +;*************************************************************************** +; * SIS960_get_mac_addr: - Get MAC address for SiS962 or SiS963 model +; * @pci_dev: the sis900 pci device +; * @net_dev: the net device to get address for +; * +; * SiS962 or SiS963 model, use EEPROM to store MAC address. And EEPROM +; * is shared by +; * LAN and 1394. When access EEPROM, send EEREQ signal to hardware first +; * and wait for EEGNT. If EEGNT is ON, EEPROM is permitted to be access +; * by LAN, otherwise is not. After MAC address is read from EEPROM, send +; * EEDONE signal to refuse EEPROM access by LAN. +; * The EEPROM map of SiS962 or SiS963 is different to SiS900. +; * The signature field in SiS962 or SiS963 spec is meaningless. +; * MAC address is read into @net_dev->dev_addr. +; *done +;* +;* Return 0 is EAX = failure +;*Done+ +;*************************************************************************** +if defined SIS900_DEBUG +SIS900_Debug_Str_GetMac_Start db 'Attempting to get SIS900 Mac ID: ',13,10,0 +SIS900_Debug_Str_GetMac_Failed db 'Access to EEprom Failed',13,10,0 +SIS900_Debug_Str_GetMac_Address db 'Your Mac ID is: ',0 +SIS900_Debug_Str_GetMac_Address2 db 'Your SIS96x Mac ID is: ',0 +end if +SIS960_get_mac_addr: + mov ebp,[io_addr] + ;**********Send Request for eeprom access********************* + lea edx,[ebp+SIS900_mear] ; Eeprom access register + mov eax, SIS900_EEREQ ; Request access to eeprom + out dx, eax ; Send request + xor ebx,ebx ; + ;******Loop 4000 times and if access not granted error out***** +SIS96X_Get_Mac_Wait: + in eax, dx ;get eeprom status + and eax, SIS900_EEGNT ;see if eeprom access granted flag is set + jnz SIS900_Got_EEP_Access ;if it is, go access the eeprom + inc ebx ;else keep waiting + cmp ebx, 4000 ;have we tried 4000 times yet? + jl SIS96X_Get_Mac_Wait ;if not ask again + xor eax, eax ;return zero in eax indicating failure + ;*******Debug ********************** +if defined SIS900_DEBUG + mov esi,SIS900_Debug_Str_GetMac_Failed + call sys_msg_board_str +end if + jmp SIS960_get_mac_addr_done + ;**********EEprom access granted, read MAC from card************* +SIS900_Got_EEP_Access: + ; zero based so 3-16 bit reads will take place + mov ecx, 2 +SIS96x_mac_read_loop: + mov eax, SIS900_EEPROMMACAddr ;Base Mac Address + add eax, ecx ;Current Mac Byte Offset + push ecx + call sis900_read_eeprom ;try to read 16 bits + pop ecx + mov [node_addr+ecx*2], ax ;save 16 bits to the MAC ID varible + dec ecx ;one less word to read + jns SIS96x_mac_read_loop ;if more read more + mov eax, 1 ;return non-zero indicating success + ;*******Debug Print MAC ID to debug window********************** +if defined SIS900_DEBUG + mov esi,SIS900_Debug_Str_GetMac_Address2 + call sys_msg_board_str + mov edx, node_addr + call Create_Mac_String +end if + ;**********Tell EEPROM We are Done Accessing It********************* +SIS960_get_mac_addr_done: + lea edx,[ebp+SIS900_mear] ; Eeprom access register + mov eax, SIS900_EEDONE ;tell eeprom we are done + out dx,eax + ret +;*************************************************************************** +;* sis900_get_mac_addr: - Get MAC address for stand alone SiS900 model +;* @pci_dev: the sis900 pci device +;* @net_dev: the net device to get address for +;* +;* Older SiS900 and friends, use EEPROM to store MAC address. +;* MAC address is read from read_eeprom() into @net_dev->dev_addr. +;* done/untested +;*************************************************************************** +SIS900_get_mac_addr: + ;*******Debug ********************** +if defined SIS900_DEBUG + mov esi,SIS900_Debug_Str_GetMac_Start + call sys_msg_board_str +end if + ;******** check to see if we have sane EEPROM ******* + mov eax, SIS900_EEPROMSignature ;Base Eeprom Signature + call sis900_read_eeprom ;try to read 16 bits + cmp ax, 0xffff + je SIS900_Bad_Eeprom + cmp ax, 0 + je SIS900_Bad_Eeprom + ;**************Read MacID************** + ; zero based so 3-16 bit reads will take place + mov ecx, 2 +SIS900_mac_read_loop: + mov eax, SIS900_EEPROMMACAddr ;Base Mac Address + add eax, ecx ;Current Mac Byte Offset + push ecx + call sis900_read_eeprom ;try to read 16 bits + pop ecx + mov [node_addr+ecx*2], ax ;save 16 bits to the MAC ID storage + dec ecx ;one less word to read + jns SIS900_mac_read_loop ;if more read more + mov eax, 1 ;return non-zero indicating success + ;*******Debug Print MAC ID to debug window********************** +if defined SIS900_DEBUG + mov esi,SIS900_Debug_Str_GetMac_Address + call sys_msg_board_str + mov edx, node_addr + call Create_Mac_String +end if + ret + +SIS900_Bad_Eeprom: + xor eax, eax + ;*******Debug ********************** +if defined SIS900_DEBUG + mov esi,SIS900_Debug_Str_GetMac_Failed + call sys_msg_board_str +end if + ret +;*************************************************************************** +;* Get_Mac_SIS635_900_REV: - Get MAC address for model 635 +;* +;* +;*************************************************************************** +Get_Mac_SIS635_900_REV: +if defined SIS900_DEBUG + mov esi,SIS900_Debug_Str_GetMac_Start + call sys_msg_board_str +end if + mov ebp,[io_addr] + lea edx,[ebp+SIS900_rfcr] + in eax,dx + mov edi,eax ; EDI=rfcrSave + lea edx,[ebp+SIS900_cr] + or eax,SIS900_RELOAD + out dx,eax + xor eax,eax + out dx,eax + ; Disable packet filtering before setting filter + lea edx,[ebp+SIS900_rfcr] + mov eax,edi + and edi,not SIS900_RFEN + out dx,eax + ; Load MAC to filter data register + xor ecx,ecx + mov esi,node_addr +.get_mac_loop: + lea edx,[ebp+SIS900_rfcr] + mov eax,ecx + shl eax,SIS900_RFADDR_shift + out dx,eax + lea edx,[ebp+SIS900_rfdr] + in eax,dx + mov [esi],ax + add esi,2 + inc ecx + cmp ecx,3 + jne .get_mac_loop + ; Enable packet filtering + ;lea edx,[ebp+SIS900_rfcr] + ;mov eax,edi + ;or eax,SIS900_RFEN + ;out dx, eax + ;*******Debug Print MAC ID to debug window********************** +if defined SIS900_DEBUG + mov esi,SIS900_Debug_Str_GetMac_Address + call sys_msg_board_str + mov edx, node_addr + call Create_Mac_String +end if + ret +;*************************************************************************** +;* Function: sis900_read_eeprom +;* +;* Description: reads and returns a given location from EEPROM +;* +;* Arguments: eax - location: requested EEPROM location +;* +;* Returns: eax : contents of requested EEPROM location +;* +; Read Serial EEPROM through EEPROM Access Register, Note that location is +; in word (16 bits) unit */ +;done+ +;*************************************************************************** +sis900_read_eeprom: + push esi + push edx + push ecx + push ebx + mov ebp,[io_addr] + mov ebx, eax ;location of Mac byte to read + or ebx, SIS900_EEread ; + lea edx,[ebp+SIS900_mear] ; Eeprom access register + xor eax, eax ; start send + out dx,eax + call SIS900_Eeprom_Delay_1 + mov eax, SIS900_EECLK + out dx, eax + call SIS900_Eeprom_Delay_1 + ;************ Shift the read command (9) bits out. ********* + mov cl, 8 ; +sis900_read_eeprom_Send: + mov eax, 1 + shl eax, cl + and eax, ebx + jz SIS900_Read_Eeprom_8 + mov eax, 9 + jmp SIS900_Read_Eeprom_9 +SIS900_Read_Eeprom_8: + mov eax, 8 +SIS900_Read_Eeprom_9: + out dx, eax + call SIS900_Eeprom_Delay_1 + or eax, SIS900_EECLK + out dx, eax + call SIS900_Eeprom_Delay_1 + cmp cl, 0 + je sis900_read_eeprom_Send_Done + dec cl + jmp sis900_read_eeprom_Send + ;********************* +sis900_read_eeprom_Send_Done: + mov eax, SIS900_EECS ; + out dx, eax + call SIS900_Eeprom_Delay_1 + ;********** Read 16-bits of data in *************** + mov cx, 16 ;16 bits to read +sis900_read_eeprom_Send2: + mov eax, SIS900_EECS + out dx, eax + call SIS900_Eeprom_Delay_1 + or eax, SIS900_EECLK + out dx, eax + call SIS900_Eeprom_Delay_1 + in eax, dx + shl ebx, 1 + and eax, SIS900_EEDO + jz SIS900_Read_Eeprom_0 + or ebx, 1 +SIS900_Read_Eeprom_0: + dec cx + jnz sis900_read_eeprom_Send2 + ;************** Terminate the EEPROM access. ************** + xor eax, eax + out dx, eax + call SIS900_Eeprom_Delay_1 + mov eax, SIS900_EECLK + out dx, eax + mov eax, ebx + and eax, 0x0000ffff ;return only 16 bits + pop ebx + pop ecx + pop edx + pop esi + ret +;*************************************************************************** +; Function +; SIS900_Eeprom_Delay_1 +; Description +; +; +; +; +;*************************************************************************** +SIS900_Eeprom_Delay_1: + push eax + in eax, dx + pop eax + ret + +;*************************************************************************** +; Function +; SIS900_poll +; Description +; polls card to see if there is a packet waiting +; +; Currently only supports one descriptor per packet, if packet is fragmented +; between multiple descriptors you will lose part of the packet +;*************************************************************************** +if defined SIS900_DEBUG +SIS900_Debug_Pull_Packet_good db 'Good Packet Waiting: ',13,10,0 +SIS900_Debug_Pull_Bad_Packet_Status db 'Bad Packet Waiting: Status',13,10,0 +SIS900_Debug_Pull_Bad_Packet_Size db 'Bad Packet Waiting: Size',13,10,0 +end if +SIS900_poll: + ;**************Get Status ************** + xor eax, eax ;get RX_Status + mov [eth_rx_data_len], ax + mov al, [cur_rx] ;find current discriptor + imul eax, 12 ; + mov ecx, [rxd+eax+4] ; get receive status + ;**************Check Status ************** + mov ebx, ecx ;move status + ;Check RX_Status to see if packet is waiting + and ebx, 0x80000000 + jnz SIS900_poll_IS_packet + ret + ;**********There is a packet waiting check it for errors************** +SIS900_poll_IS_packet: + mov ebx, ecx ;move status + and ebx, 0x67C0000 ;see if there are any errors + jnz SIS900_Poll_Error_Status + ;**************Check size of packet************* + and ecx, SIS900_DSIZE ;get packet size minus CRC + cmp cx, SIS900_CRC_SIZE + ;make sure packet contains data + jle SIS900_Poll_Error_Size + ;*******Copy Good Packet to receive buffer****** + sub cx, SIS900_CRC_SIZE ;dont want crc + mov word [eth_rx_data_len], cx ;save size of packet + ;**********Continue copying packet**************** + push ecx + ; first copy dword-wise, divide size by 4 + shr ecx, 2 + mov esi, [rxd+eax+8] ; set source + mov edi, Ether_buffer ; set destination + cld ; clear direction + rep movsd ; copy the dwords + pop ecx + and ecx, 3 ; + rep movsb + ;********Debug, tell user we have a good packet************* +if defined SIS900_DEBUG + mov esi, SIS900_Debug_Pull_Packet_good + call sys_msg_board_str +end if + jmp SIS900_Poll_Cnt ; + ;*************Error occured let user know through debug window*********** +SIS900_Poll_Error_Status: +if defined SIS900_DEBUG + mov esi, SIS900_Debug_Pull_Bad_Packet_Status + call sys_msg_board_str +end if + jmp SIS900_Poll_Cnt +SIS900_Poll_Error_Size: +if defined SIS900_DEBUG + mov esi, SIS900_Debug_Pull_Bad_Packet_Size + call sys_msg_board_str +end if + ;*************Increment to next available descriptor************** +SIS900_Poll_Cnt: + ;Reset status, allow ethernet card access to descriptor + mov ecx, RX_BUFF_SZ + mov [rxd+eax+4], ecx ; + inc [cur_rx] ;get next descriptor + and [cur_rx],3 ;only 4 descriptors 0-3 + ;******Enable Receiver************ + mov ebp, [io_addr] ; Base Address + lea edx,[ebp+SIS900_cr] ; Command Register offset + in eax, dx ; Get current Command Register + or eax, SIS900_RxENA ;Enable Receive + out dx, eax + ret +;*************************************************************************** +; Function +; SIS900_transmit +; Description +; Transmits a packet of data via the ethernet card +; Pointer to 48 bit destination address in edi +; Type of packet in bx +; size of packet in ecx +; pointer to packet data in esi +; +; only one transmit descriptor is used +; +;*************************************************************************** +if defined SIS900_DEBUG +SIS900_Debug_Transmit_Packet db 'Transmitting Packet: ',13,10,0 +SIS900_Debug_Transmit_Packet_Err db 'Transmitting Packet Error: ',13,10,0 +end if +SIS900_transmit: + mov ebp, [io_addr] ; Base Address + ;******** Stop the transmitter ******** + lea edx,[ebp+SIS900_cr] ; Command Register offset + in eax, dx ; Get current Command Register + or eax, SIS900_TxDIS ; Disable Transmitter + out dx, eax + ;*******load Transmit Descriptor Register ******* + lea edx,[ebp+SIS900_txdp] + mov eax, txd + out dx, eax + ;******* copy packet to descriptor******* + push esi + mov esi, edi ;copy destination addess + mov edi, txb + cld + movsd + movsw + mov esi, node_addr ;copy my mac address + movsd + movsw + mov [edi], bx ;copy packet type + add edi, 2 + pop esi ;restore pointer to source of packet + push ecx ;save packet size + shr ecx, 2 ;divide by 4, size in bytes send in dwords + rep movsd ;copy data to decriptor + pop ecx ;restore packet size + push ecx ;save packet size + and ecx, 3 ;last three bytes if not a multiple of 4 + rep movsb + ;**************set length tag************** + pop ecx ;restore packet size + add ecx, SIS900_ETH_HLEN ;add header to length + and ecx, SIS900_DSIZE ; + ;**************pad to minimum packet size **************not needed + ;cmp ecx, SIS900_ETH_ZLEN + ;jge SIS900_transmit_Size_Ok + ;push ecx + ;mov ebx, SIS900_ETH_ZLEN + ;sub ebx, ecx + ;mov ecx, ebx + ;rep movsb + ;pop ecx +SIS900_transmit_Size_Ok: + mov [txd+4], dword 0x80000000 ;card owns descriptor + or [txd+4], ecx ;set size of packet +if defined SIS900_DEBUG + mov esi, SIS900_Debug_Transmit_Packet + call sys_msg_board_str +end if + ;***************restart the transmitter ******** + lea edx,[ebp+SIS900_cr] + in eax, dx ; Get current Command Register + or eax, SIS900_TxENA ; Enable Transmitter + out dx, eax + ;****make sure packet transmitted successfully**** +; mov esi,10 +; call delay_ms + mov eax, [txd+4] + and eax, 0x6200000 + jz SIS900_transmit_OK + ;**************Tell user there was an error through debug window +if defined SIS900_DEBUG + mov esi, SIS900_Debug_Transmit_Packet_Err + call sys_msg_board_str +end if +SIS900_transmit_OK: + ;******** Disable interrupts by clearing the interrupt mask. ******** + lea edx,[ebp+SIS900_imr] ; Interupt Mask Register + xor eax, eax + out dx,eax + ret + +;*************************************************************************** +;* Function: Create_Mac_String +;* +;* Description: Converts the 48 bit value to a string for display +;* +;* String Format: XX:XX:XX:XX:XX:XX +;* +;* Arguments: node_addr is location of 48 bit MAC ID +;* +;* Returns: Prints string to general debug window +;* +;* +;done +;*************************************************************************** +if defined SIS900_DEBUG + +SIS900_Char_String db '0','1','2','3','4','5','6','7','8','9' + db 'A','B','C','D','E','F' +Mac_str_build: times 20 db 0 +Create_Mac_String: + pusha + xor ecx, ecx +Create_Mac_String_loop: + mov al,byte [edx+ecx];[node_addr+ecx] + push eax + shr eax, 4 + and eax, 0x0f + mov bl, byte [SIS900_Char_String+eax] + mov [Mac_str_build+ecx*3], bl + pop eax + and eax, 0x0f + mov bl, byte [SIS900_Char_String+eax] + mov [Mac_str_build+1+ecx*3], bl + cmp ecx, 5 + je Create_Mac_String_done + mov bl, ':' + mov [Mac_str_build+2+ecx*3], bl + inc ecx + jmp Create_Mac_String_loop +Create_Mac_String_done: ;Insert CR and Zero Terminate + mov [Mac_str_build+2+ecx*3],byte 13 + mov [Mac_str_build+3+ecx*3],byte 10 + mov [Mac_str_build+4+ecx*3],byte 0 + mov esi, Mac_str_build + call sys_msg_board_str ;Print String to message board + popa + ret +end if +;*************************************************************************** +;* Set device to be a busmaster in case BIOS neglected to do so. +;* Also adjust PCI latency timer to a reasonable value, 64. +;*************************************************************************** +SIS900_adjust_pci_device: + ;*******Get current setting************************ + mov al, 2 ;read a word + mov bh, [pci_dev] + mov ah, [pci_bus] + mov bl, 0x04 ;from command Register + call pci_read_reg + ;******see if its already set as bus master******** + mov bx, ax + and bx,5 + cmp bx,5 + je SIS900_adjust_pci_device_Latency + ;******Make card a bus master******* + mov cx, ax ;value to write + mov bh, [pci_dev] + mov al, 2 ;write a word + or cx,5 + mov ah, [pci_bus] + mov bl, 0x04 ;to command register + call pci_write_reg + ;******Check latency setting*********** +SIS900_adjust_pci_device_Latency: + ;*******Get current latency setting************************ + mov al, 1 ;read a byte + mov bh, [pci_dev] + mov ah, [pci_bus] + mov bl, 0x0D ;from Lantency Timer Register + call pci_read_reg + ;******see if its aat least 64 clocks******** + cmp ax,64 + jge SIS900_adjust_pci_device_Done + ;******Set latency to 32 clocks******* + mov cx, 64 ;value to write + mov bh, [pci_dev] + mov al, 1 ;write a byte + mov ah, [pci_bus] + mov bl, 0x0D ;to Lantency Timer Register + call pci_write_reg + ;******Check latency setting*********** +SIS900_adjust_pci_device_Done: + ret diff --git a/kernel/trunk/network/eth_drv/ethernet.inc b/kernel/trunk/network/eth_drv/ethernet.inc index b72be5b685..e6db415655 100644 --- a/kernel/trunk/network/eth_drv/ethernet.inc +++ b/kernel/trunk/network/eth_drv/ethernet.inc @@ -36,6 +36,22 @@ ; ;******************************************************************** +ETHER_IP equ 0x0008 ; Reversed from 0800 for intel +ETHER_ARP equ 0x0608 ; Reversed from 0806 for intel +ETHER_RARP equ 0x3580 + +struc ETH_FRAME +{ .DstMAC dp ? ;destination MAC-address [6 bytes] + .SrcMAC dp ? ;source MAC-address [6 bytes] + .Type dw ? ;type of the upper-layer protocol [2 bytes] + .Data db ? ;data [46-1500 bytes] +} + +virtual at Ether_buffer + ETH_FRAME ETH_FRAME +end virtual + + ; Some useful information on data structures ; Ethernet Packet - ARP Request example @@ -75,18 +91,12 @@ ; Include individual drivers source files at this point. ; If you create a new driver, include it below. -include "rtl8029.inc" -include "i8255x.inc" -include "rtl8139.inc" -include "3c59x.inc" -include "sis900.inc" -include "pcnet32.inc" - -; DEBUGGING_STATE enables or disables output of received and transmitted -; data over the serial port -DEBUGGING_ENABLED equ 1 -DEBUGGING_DISABLED equ 0 -DEBUGGING_STATE equ DEBUGGING_DISABLED +include "drivers/rtl8029.inc" +include "drivers/i8255x.inc" +include "drivers/rtl8139.inc" +include "drivers/3c59x.inc" +include "drivers/sis900.inc" +include "drivers/pcnet32.inc" ; PCICards ; ======== @@ -173,26 +183,12 @@ dd 0x70161039, SIS900_probe, SIS900_reset, SIS900_poll, SIS900_transmit dd 0,0,0,0,0 ; end of list marker, do not remove endg -; PCI Bus defines -PCI_HEADER_TYPE equ 0x0e ;8 bit -PCI_BASE_ADDRESS_0 equ 0x10 ;32 bit -PCI_BASE_ADDRESS_5 equ 0x24 ;32 bits -PCI_BASE_ADDRESS_SPACE_IO equ 0x01 -PCI_VENDOR_ID equ 0x00 ;16 bit -PCI_BASE_ADDRESS_IO_MASK equ 0xFFFFFFFC - -ETHER_IP equ 0x0008 ; Reversed from 0800 for intel -ETHER_ARP equ 0x0608 ; Reversed from 0806 for intel -ETHER_RARP equ 0x3580 -ARP_REQ_OPCODE equ 0x0100 -ARP_REP_OPCODE equ 0x0200 - uglobal - arp_rx_count: dd 0 - ip_rx_count: dd 0 - dumped_rx_count: dd 0 - ip_tx_count: dd 0 +;Net-stack's interface's settings node_addr: db 0,0,0,0,0,0 + gateway_ip: db 0, 0, 0, 0 + dns_ip: dd 0 + eth_rx_data_len: dw 0 eth_status: dd 0 io_addr: dd 0 @@ -208,59 +204,143 @@ uglobal drvr_poll: dd 0 drvr_transmit: dd 0 - ; These hold the destination Host identity for ARP responses - remote_ip_add: dd 0 - remote_hw_add: db 0, 0, 0, 0, 0, 0 endg iglobal broadcast_add: db 0xff,0xff,0xff,0xff,0xff,0xff - subnet_mask: dd 0x00ffffff + subnet_mask: dd 0x00ffffff ; 255.255.255.0 endg -uglobal - ; This is used by getMACfromIP - MACAddress: db 0,0,0,0,0,0 - gateway_ip: db 0, 0, 0, 0 - dns_ip: dd 0 -endg +include "arp.inc" ;arp-protocol functions +include "pci.inc" ;PCI bus access functions -; The follow is the ARP Table. -; This table must be manually updated and the kernel recompilied if -; changes are made to it. -; ARP_TABLE_SIZE defines the size of the table -; ARP_TABLE_ENTRIES defines the number of entries in the table -; Each entry is 10 bytes: 4 Byte IP address, 6 byte MAC Address, -; 2 bytes status, 2 bytes TTL ( in seconds ) -; Empty entries are filled with zeros -; The TTL field is decremented every second, and is deleted when it -; reaches 0. It is refreshed every time a packet is received -; If the TTL field is 0xFFFF it is a permanent entry and is never deleted -; The status field can be the following values -; 0x0000 entry not used -; 0x0001 entry holds a valid mapping -; 0x0002 entry contains an IP address, awaiting ARP response -; 0x0003 No response received to ARP request. -; The last status value is provided to allow the network layer to delete -; a packet that is queued awaiting an ARP response -ARP_NO_ENTRY equ 0 -ARP_VALID_MAPPING equ 1 -ARP_AWAITING_RESPONSE equ 2 -ARP_RESPONSE_TIMEOUT equ 3 +;*************************************************************************** +; Function +; eth_tx +; +; Description +; Looks at the NET1OUT_QUEUE for data to send. +; Stores that destination IP in a location used by the tx routine +; Looks up the MAC address in the ARP table; stores that where +; the tx routine can get it +; Get the length of the data. Store that where the tx routine wants it +; Call tx +; Places buffer on empty queue when the tx routine finished +; +;*************************************************************************** +proc eth_tx stdcall uses ebx esi edi +local MACAddress dp ? ;allocate 6 bytes in the stack -ARP_ENTRY_SIZE equ 14 ; Number of bytes per entry -ARP_TABLE_SIZE equ 20 ; Size of table -ARP_TABLE_ENTRIES equ 0 ; Inital, hardcoded entries + ; Look for a buffer to tx + mov eax, NET1OUT_QUEUE + call dequeue + cmp ax, NO_BUFFER + je .exit ; Exit if no buffer available -uglobal - ARPTable: - times ( ARP_TABLE_SIZE - ARP_TABLE_ENTRIES ) * ARP_ENTRY_SIZE db 0 -endg + push eax ;save buffer number -iglobal - NumARP: db ARP_TABLE_ENTRIES -endg + ; convert buffer pointer eax to the absolute address + imul eax, IPBUFFSIZE + add eax, IPbuffs + + ; Extract the destination IP + ; find the destination IP in the ARP table, get MAC + ; store this MAC in 'MACAddress' + mov ebx, eax ; Save buffer address + mov edx, [ebx + 16] ; get destination address + + ; If the destination address is 255.255.255.255, + ; set the MACAddress to all ones ( broadcast ) + cld + mov esi, broadcast_add + lea edi, [MACAddress] + movsd + movsw + cmp edx, 0xffffffff + je .send ; If it is broadcast, just send + + lea eax, [MACAddress] ;cause this is local variable + stdcall arp_table_manager, ARP_TABLE_IP_TO_MAC, edx, eax ;opcode,IP,MAC_ptr - Get the MAC address. + + cmp eax, ARP_VALID_MAPPING + je .send + + ; No valid entry. Has the request been sent, but timed out? + cmp eax, ARP_RESPONSE_TIMEOUT + je .freebuf + + .wait_response: ;we wait arp-response + ; Re-queue the packet, and exit + pop ebx + mov eax, NET1OUT_QUEUE + call queue ; Get the buffer back + jmp .exit + + .send: ;if ARP_VALID_MAPPING then send the packet + lea edi, [MACAddress] ; Pointer to 48 bit destination address + movzx ecx, word[ebx+2] ; Size of IP packet to send + xchg ch, cl ; because mirror byte-order + mov esi, ebx ; Pointer to packet data + mov bx, ETHER_IP ; Type of packet + call dword [drvr_transmit] ; Call the drivers transmit function + + ; OK, we have sent a packet, so increment the count + inc dword [ip_tx_count] + + ; And finally, return the buffer to the free queue + .freebuf: + pop eax + call freeBuff + + .exit: + ret +endp + +;*************************************************************************** +; Function +; ether_IP_handler +; +; Description +; Called when an IP ethernet packet is received on the ethernet +; Header + Data is in Ether_buffer[] +; We just need to get a buffer from the 'free' queue, and +; store the packet in it, then insert the packet number into the +; IPRX queue. +; If no queue entry is available, the packet is silently discarded +; All registers may be destroyed +; +;*************************************************************************** +ether_IP_handler: + mov eax, EMPTY_QUEUE + call dequeue + cmp ax, NO_BUFFER + je eiph00x + + ; convert buffer pointer eax to the absolute address + push eax + mov ecx, IPBUFFSIZE + mul ecx + add eax, IPbuffs + + mov edi, eax + + ; get a pointer to the start of the DATA + mov esi, ETH_FRAME.Data + + ; Now store it all away + mov ecx, IPBUFFSIZE / 4 ; Copy all of the available + ; data across - worse case + cld + rep movsd + + ; And finally, place the buffer in the IPRX queue + pop ebx + mov eax, IPIN_QUEUE + call queue + +eiph00x: + ret ;*************************************************************************** ; Function @@ -327,1375 +407,30 @@ eth_rx: mov ax, [eth_rx_data_len] cmp ax, 0 - je erx_exit + je .exit -if DEBUGGING_STATE = DEBUGGING_ENABLED - pusha - mov eax, 0 ;Indicate that this is a received packet - mov cx, [eth_rx_data_len] - mov esi, Ether_buffer - cmp word [esi + 12], ETHER_IP - jnz erxd_done -; cmp byte [esi + 14 + 9], 0x06 ; TCP -; jnz erxd_done - call eth_dump -erxd_done: - popa -end if ; Check the protocol. Call appropriate handler - mov eax, Ether_buffer - add eax, 12 ; The address of the protocol word - mov ax, [eax] - - cmp ax, ETHER_ARP - je erx_001 ; It is ARP + mov ax, [ETH_FRAME.Type] ; The address of the protocol word cmp ax, ETHER_IP - je erx_002 ; It's IP + je .is_ip ; It's IP -; inc dword [dumped_rx_count] + cmp ax, ETHER_ARP + je .is_arp ; It is ARP - jmp erx_exit ; If not IP or ARP, ignore + jmp .exit ; If not IP or ARP, ignore -erx_001: - mov eax, [arp_rx_count] - inc eax - mov [arp_rx_count], eax + .is_ip: + inc dword [ip_rx_count] + call ether_IP_handler + jmp .exit + + .is_arp: ; At this point, the packet is still in the Ether_buffer call arp_handler - jmp erx_exit - -erx_002: - mov eax, [ip_rx_count] - inc eax - mov [ip_rx_count], eax - - ; Check to see if the MAC address is in our arp table - ; refresh the arp ttl if so - - mov esi, Ether_buffer - add esi, 6 - - call refreshARP - - call ether_IP_handler - - jmp erx_exit - -erx_exit: - ret - -;*************************************************************************** -; Function -; eth_tx -; -; Description -; Looks at the NET1OUT_QUEUE for data to send. -; Stores that destination IP in a location used by the tx routine -; Looks up the MAC address in the ARP table; stores that where -; the tx routine can get it -; Get the length of the data. Store that where the tx routine wants it -; Call tx -; Places buffer on empty queue when the tx routine finished -; -;*************************************************************************** -eth_tx: - ; Look for a buffer to tx - mov eax, NET1OUT_QUEUE - call dequeue - cmp ax, NO_BUFFER - je eth_exit ; Exit if no buffer available - - push eax - - ; convert buffer pointer eax to the absolute address - mov ecx, IPBUFFSIZE - mul ecx - add eax, IPbuffs - - ; Extract the destination IP - ; find the destination IP in the ARP table, get MAC - ; store this MAC in 'MACAddress' - mov ebx, eax ; Save buffer address - mov edx, [ebx + 16] ; get destination address - - ; If the destination address is 255.255.255.255, - ; set the MACAddress to all ones ( broadcast ) - mov [MACAddress], dword 0xffffffff - mov [MACAddress + 4], word 0xffff - cmp edx, 0xffffffff - je etx_send ; If it is broadcast, just send - - call getMACfromIP ; Get the MAC address. - - cmp eax, ARP_VALID_MAPPING - jz etx_send - - ; No valid entry. Are we waiting for a response? - cmp eax, ARP_AWAITING_RESPONSE - jne etx_001 - - ; Re-queue the packet, and exit - pop ebx - mov eax, NET1OUT_QUEUE - call queue - jmp etx_exit - -etx_001: - ; HAs the request been sent, but timed out? - cmp eax, ARP_RESPONSE_TIMEOUT - jne etx_002 - - pop eax - call freeBuff - jmp etx_exit - -etx_002: - ; There is no entry. Re queue the request, and ask ARP to send a request - - ; IP address is in edx - push edx - call arp_request - pop ebx - - ; Add an entry in the ARP table, awaiting response - - cmp byte [NumARP], ARP_TABLE_SIZE - je etx_003 ; We cannot add a new entry in the table - - inc byte [NumARP] - - movzx eax, byte [NumARP] - mov ecx, ARP_ENTRY_SIZE - mul ecx - sub eax, ARP_ENTRY_SIZE - - mov [eax + ARPTable], ebx - xor ebx, ebx - mov [eax + ARPTable + 4], ebx - mov [eax + ARPTable + 8], bx - - ; set the status field up - awaiting response - mov cl, 0x00 - mov [eax + ARPTable + 10], cl - mov cl, 0x02 - mov [eax + ARPTable + 11], cl - - ; Initialise the time to live field - 10s - mov cx, 0x000A - mov [eax + ARPTable + 12], cx - -etx_003: - pop ebx ; Get the buffer back - mov eax, NET1OUT_QUEUE - call queue - jmp etx_exit - -etx_send: - xor ecx, ecx - mov ch, [ebx+2] - mov cl, [ebx+3] ; ; Size of IP packet to send - - mov esi, ebx - - mov edi, MACAddress - -if DEBUGGING_STATE = DEBUGGING_ENABLED - pusha - mov cx, 42 - mov eax, 1 ; Indicate that this is a tx packet - call eth_dump - popa -end if - - mov bx, ETHER_IP - call dword [drvr_transmit] ; Call the drivers transmit function - - ; OK, we have sent a packet, so increment the count - inc dword [ip_tx_count] - - ; And finally, return the buffer to the free queue - pop eax - call freeBuff - -etx_exit: - ret - -;*************************************************************************** -; Function -; ether_IP_handler -; -; Description -; Called when an IP ethernet packet is received on the ethernet -; Header + Data is in Ether_buffer[] -; We just need to get a buffer from the 'free' queue, and -; store the packet in it, then insert the packet number into the -; IPRX queue. -; If no queue entry is available, the packet is silently discarded -; All registers may be destroyed -; -;*************************************************************************** -ether_IP_handler: - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je eiph00x - - ; convert buffer pointer eax to the absolute address - push eax - mov ecx, IPBUFFSIZE - mul ecx - add eax, IPbuffs - - mov edi, eax - - ; get a pointer to the start of the DATA - mov esi, Ether_buffer + 14 - - ; Now store it all away - mov ecx, IPBUFFSIZE / 4 ; Copy all of the available - ; data across - worse case - cld - rep movsd - - ; And finally, place the buffer in the IPRX queue - pop ebx - mov eax, IPIN_QUEUE - call queue - -eiph00x: - ret - -;*************************************************************************** -; -; ARP CODE FOLLOWS -; -; The ARP code is used by ethernet drivers to translate an destination -; IP address into an ethernet hardware address. Functions to broadcast -; requests and handle response are (or will be) here. -; The IP layer has no knowledge of ARP, as this is a network interface -; issue -; -;*************************************************************************** - -;*************************************************************************** -; Function -; arp_timer -; -; Description -; Called every 1s -; It is responsible for removing expired routes -; All registers may be destroyed -; -;*************************************************************************** -arp_timer: - ; loop through all the ARP entries, decrementing each one - ; that doesn't have a TTL of 0xFFFF - movzx eax, byte [NumARP] - -arp_001: - cmp eax, 0 - je arp_003 - - push eax - dec eax - mov ecx, ARP_ENTRY_SIZE - mul ecx - cmp word [ eax + ARPTable + 12], 0xFFFF - je arp_002 - - cmp word [ eax + ARPTable + 12], 0 - je arp_002 - - dec word [eax + ARPTable + 12] - -arp_002: - pop eax - dec eax - jmp arp_001 - - ; Now, look for entries with a TTL of 0 - ; Valid entries and response timeout entries get removed - ; awaiting response gets converted into a response timeout, with a - ; short life time - this allows queued packets to be flushed -arp_003: - movzx edx, byte [NumARP] - cmp edx, 0 - je arp_exit - - ; EDX holds the # of entries to search through - mov eax, 0 - -arp_005: - cmp word [ eax + ARPTable + 12], 0 - jne arp_004 - - ; If it's status code is 0001 or 0003, delete the entry - cmp word [eax + ARPTable + 10], 0x0100 - je arp_007 - cmp word [eax + ARPTable + 10], 0x0300 - je arp_007 - - ; The only other valid code is 0002 - indicating a - ; timeout while waiting for a response. Change the - ; entry to response timed out - - mov [eax + ARPTable + 10], word 0x0300 - mov [eax + ARPTable + 12], word 0x000A - jmp arp_004 - -arp_007: - ; Delete this entry - mov edi, ARPTable - add edi, eax - mov esi, edi - add esi, ARP_ENTRY_SIZE - - mov ecx, (ARP_TABLE_SIZE - 1) * ARP_ENTRY_SIZE - sub ecx, eax - - rep movsb - - dec byte [NumARP] - jmp arp_006 - -arp_004: - add eax, ARP_ENTRY_SIZE -arp_006: - dec edx - cmp edx, 0 - jne arp_005 - -arp_exit: - ret - -;*************************************************************************** -; Function -; arp_request -; -; Description -; Sends an ARP request on the ethernet -; The requested IP address is in edx -; All registers may be destroyed -; -;*************************************************************************** -arp_request: - mov ebx, Ether_buffer - mov ax, 0x0100 - mov [ebx], ax - add ebx, 2 - - mov ax, 0x0008 - mov [ebx], ax - add ebx, 2 - - mov ax, 0x0406 - mov [ebx], ax - add ebx, 2 - - mov ax, 0x0100 - mov [ebx], ax - add ebx, 2 - - mov ecx, node_addr - mov eax, [ecx] - mov [ebx], eax - add ecx, 4 - add ebx, 4 - mov ax, [ecx] - mov [ebx], ax - add ebx, 2 - mov eax, [stack_ip] - mov [ebx], eax - add ebx, 4 - - xor eax, eax - mov [ebx], eax - add ebx, 4 - mov [ebx], ax - - add ebx, 2 - mov [ebx], edx - - ; Now, send it! - - ; Pointer to 48 bit destination address in edi - ; Type of packet in bx - ; size of packet in ecx - ; pointer to packet data in esi - mov edi, broadcast_add - -;if DEBUGGING_STATE = DEBUGGING_ENABLED -; pusha -; mov eax, 1 ; Indicate that this is a tx packet -; mov ecx, 28 -; mov esi, Ether_buffer -; call eth_dump -; popa -;end if - - mov bx, ETHER_ARP - mov ecx, 28 - mov esi, Ether_buffer - call dword [drvr_transmit] ; Call the drivers transmit function - ret - -;*************************************************************************** -; Function -; arp_handler -; -; Description -; Called when an ARP packet is received on the ethernet -; Header + Data is in Ether_buffer[] -; It looks to see if the packet is a request to resolve this Hosts -; IP address. If it is, send the ARP reply packet. -; This Hosts IP address is in dword [stack_ip] ( in network format ) -; This Hosts MAC address is in node_addr[6] -; All registers may be destroyed -; -;*************************************************************************** -arp_handler: - ; Is this a REQUEST? - ; Is this a request for My Host IP - ; Yes - So construct a response message. - ; Send this message to the ethernet card for transmission - - mov ebx, Ether_buffer - - mov edx, ebx - add edx, 20 - mov ax, [edx] - cmp ax, ARP_REQ_OPCODE ; Is this a request packet? - jne arph_resp ; No - so test for response - - mov edx, ebx - add edx, 38 - mov eax, [edx] - - cmp eax, [stack_ip] ; Is it looking for my IP address? - jne arph_exit ; No - so quit now - - ; OK, it is a request for my MAC address. Build the frame and send it - - ; Save the important data from the original packet - ; remote MAC address first - mov ecx, remote_hw_add - mov edx, ebx - add edx, 22 ; edx points to Source h/w address - mov eax, [edx] - mov [ecx], eax - add edx, 4 - add ecx, 4 - mov ax, [edx] - mov [ecx],ax - - ; and also the remote IP address - add edx, 2 - mov eax,[edx] - mov [remote_ip_add], eax - - ; So now we can reuse the packet. ebx still holds the address of - ; the header + packet - ; We dont need the header ( first 14 bytes ) - - mov edx, ebx - add edx, 20 - mov ax, ARP_REP_OPCODE - mov [edx], ax - add edx, 2 - - mov ecx, node_addr - mov eax, [ecx] - mov [edx], eax - add ecx, 4 - add edx, 4 - mov ax, [ecx] - mov [edx], ax - add edx, 2 - mov eax, [stack_ip] - mov [edx], eax - add edx, 4 - mov ecx, remote_hw_add - mov eax, [ecx] - mov [edx], eax - add ecx, 4 - add edx, 4 - mov ax, [ecx] - mov [edx], ax - - add edx, 2 - mov eax, [remote_ip_add] - mov [edx], eax - - ; Now, send it! - - ; Pointer to 48 bit destination address in edi - ; Type of packet in bx - ; size of packet in ecx - ; pointer to packet data in esi - mov edi, remote_hw_add - -;if DEBUGGING_STATE = DEBUGGING_ENABLED -; pusha -; mov eax, 1 ; Indicate that this is a tx packet -; mov ecx, 28 -; mov esi, Ether_buffer + 14 - ; call eth_dump -; popa -;end if - - mov bx, ETHER_ARP - mov ecx, 28 - mov esi, Ether_buffer + 14 - call dword [drvr_transmit] ; Call the drivers transmit function - jmp arph_exit - -arph_resp: - cmp ax, ARP_REP_OPCODE ; Is this a replypacket? - jne arph_resp ; No - so quit - - ; This was a reply, probably directed at me. - ; save the remotes MAC & IP - mov ecx, remote_hw_add - mov edx, ebx - add edx, 22 ; edx points to Source h/w address - mov eax, [edx] - mov [ecx], eax - add edx, 4 - add ecx, 4 - mov ax, [edx] - mov [ecx],ax - - ; and also the remote IP address - add edx, 2 - mov eax,[edx] - mov [remote_ip_add], eax - - ; Now, add an entry in the table for this IP address if it doesn't exist - - push eax - movzx eax, byte [NumARP] - mov ecx, ARP_ENTRY_SIZE - mul ecx - pop edx - movzx ecx, byte [NumARP] - cmp ecx, 0 - je arph_002 - -arph_001: - sub eax, ARP_ENTRY_SIZE - cmp [eax + ARPTable], edx - loopnz arph_001 ; Return back if non match - - jnz arph_002 ; None found, add to end - - mov ecx, [remote_hw_add] - mov [eax + ARPTable + 4], ecx - mov cx, [remote_hw_add+4] - mov [eax + ARPTable + 8], cx - - ; specify the type - a valid entry - mov cl, 0x00 - mov [eax + ARPTable + 10], cl - mov cl, 0x01 - mov [eax + ARPTable + 11], cl - - ; Initialise the time to live field - 1 hour - mov cx, 0x0E10 - mov [eax + ARPTable + 12], cx - jmp arph_exit - -arph_002: - - cmp byte [NumARP], ARP_TABLE_SIZE - je arph_exit - - inc byte [NumARP] - - movzx eax, byte [NumARP] - mov ecx, ARP_ENTRY_SIZE - mul ecx - sub eax, ARP_ENTRY_SIZE - - mov ecx, [remote_ip_add] - mov [eax + ARPTable], ecx - mov ecx, [remote_hw_add] - mov [eax + ARPTable + 4], ecx - mov cx, [remote_hw_add+4] - mov [eax + ARPTable + 8], cx - - mov cl, 0x00 - mov [eax + ARPTable + 10], cl - mov cl, 0x01 - mov [eax + ARPTable + 11], cl - - ; Initialise the time to live field - 1 hour - mov cx, 0x0E10 - mov [eax + ARPTable + 12], cx - -arph_exit: - ret - -; pointer to MAC in esi -refreshARP: - mov ebx, [esi] - mov dx, [esi+4] - push edx - movzx eax, byte [NumARP] - mov ecx, ARP_ENTRY_SIZE - mul ecx - pop edx - movzx ecx, byte [NumARP] - cmp ecx, 0 - je rf_exit - -rf_001: - sub eax, ARP_ENTRY_SIZE - cmp [eax + ARPTable+4], ebx - - je rf_002 - loop rf_001 - jmp rf_exit - -rf_002: - cmp [eax + ARPTable+8], dx - je rf_gotone - loop rf_001 - jmp rf_exit - -rf_gotone: - ; Initialise the time to live field - 1 hour - mov cx, 0x0E10 - mov [eax + ARPTable + 12], cx - -rf_exit: - ret - -;*************************************************************************** -; Function -; getMACfromIP -; -; Description -; Takes an IP address in edx and scans the ARP table for -; a matching entry -; If a match is found, it's MAC address is stored in MACAddress. -; Otherwise the value 0 is writen to MACAddress -; eax holds ARP table entry status code ( ARP_ ) -; ebx unchanged -; -;*************************************************************************** -getMACfromIP: - ; first, check destination IP to see if it is on 'this' network. - ; The test is: - ; if ( destIP & subnet_mask == stack_ip & subnet_mask ) - ; desitnation is local - ; else - ; destination is remote, so pass to gateway - - mov eax, edx - and eax, [subnet_mask] - mov ecx, [stack_ip] - and ecx, [subnet_mask] - cmp eax, ecx - je gm0 - - mov edx, [gateway_ip] -gm0: - push edx - xor eax, eax - mov [MACAddress], eax - mov [MACAddress + 4], ax - - movzx eax, byte [NumARP] - mov ecx, ARP_ENTRY_SIZE - mul ecx - - pop edx - - movzx ecx, byte [NumARP] - cmp ecx, 0 - je gm_none -gm1: - sub eax, ARP_ENTRY_SIZE - cmp [eax + ARPTable], edx - loopnz gm1 ; Return back if non match - jnz gm_none ; Quit if none found - - ; eax holds index - mov ecx, [eax + ARPTable + 4] - mov [MACAddress], ecx - mov cx, [eax + ARPTable + 8] - mov [MACAddress+4], cx - - ; Return the entry status in eax - mov ch, [eax + ARPTable + 10] - mov cl, [eax + ARPTable + 11] - movzx eax, cx - jmp gm_exit - -gm_none: - mov eax, ARP_NO_ENTRY - -gm_exit: - ret - -;*************************************************************************** -; -; PCI CODE FOLLOWS -; -; the following functions provide access to the PCI interface. -; These functions are used by scan_bus, and also some ethernet drivers -; -;*************************************************************************** - -;*************************************************************************** -; Function -; config_cmd -; -; Description -; creates a command dword for use with the PCI bus -; bus # in ebx -; devfn in ecx -; where in edx -; -; command dword returned in eax -; Only eax destroyed -;*************************************************************************** -config_cmd: - push ecx - mov eax, ebx - shl eax, 16 - or eax, 0x80000000 - shl ecx, 8 - or eax, ecx - pop ecx - or eax, edx - and eax, 0xFFFFFFFC - ret - -;*************************************************************************** -; Function -; pcibios_read_config_byte -; -; Description -; reads a byte from the PCI config space -; bus # in ebx -; devfn in ecx -; where in edx ( ls 16 bits significant ) -; -; byte returned in al ( rest of eax zero ) -; Only eax/edx destroyed -;*************************************************************************** -pcibios_read_config_byte: - call config_cmd - push dx - mov dx, 0xCF8 - out dx, eax - pop dx - - xor eax, eax - and dx, 0x03 - add dx, 0xCFC -; and dx, 0xFFC - in al, dx - ret - -;*************************************************************************** -; Function -; pcibios_read_config_word -; -; Description -; reads a word from the PCI config space -; bus # in ebx -; devfn in ecx -; where in edx ( ls 16 bits significant ) -; -; word returned in ax ( rest of eax zero ) -; Only eax/edx destroyed -;*************************************************************************** -pcibios_read_config_word: - call config_cmd - push dx - mov dx, 0xCF8 - out dx, eax - pop dx - - xor eax, eax - and dx, 0x02 - add dx, 0xCFC -; and dx, 0xFFC - in ax, dx - ret - -;*************************************************************************** -; Function -; pcibios_read_config_dword -; -; Description -; reads a dword from the PCI config space -; bus # in ebx -; devfn in ecx -; where in edx ( ls 16 bits significant ) -; -; dword returned in eax -; Only eax/edx destroyed -;*************************************************************************** -pcibios_read_config_dword: - push edx - call config_cmd - push dx - mov dx, 0xCF8 - out dx, eax - pop dx - xor eax, eax - mov dx, 0xCFC - in eax, dx - pop edx - ret - -;*************************************************************************** -; Function -; pcibios_write_config_byte -; -; Description -; write a byte in al to the PCI config space -; bus # in ebx -; devfn in ecx -; where in edx ( ls 16 bits significant ) -; -; Only eax/edx destroyed -;*************************************************************************** -pcibios_write_config_byte: - push ax - call config_cmd - push dx - mov dx, 0xCF8 - out dx, eax - pop dx - pop ax - - and dx, 0x03 - add dx, 0xCFC - out dx, al - ret - -;*************************************************************************** -; Function -; pcibios_write_config_word -; -; Description -; write a word in ax to the PCI config space -; bus # in ebx -; devfn in ecx -; where in edx ( ls 16 bits significant ) -; -; Only eax/edx destroyed -;*************************************************************************** -pcibios_write_config_word: - push ax - call config_cmd - push dx - mov dx, 0xCF8 - out dx, eax - pop dx - pop ax - - and dx, 0x02 - add dx, 0xCFC - out dx, ax - ret - -;*************************************************************************** -; Function -; delay_us -; -; Description -; delays for 30 to 60 us -; -; I would prefer this routine to be able to delay for -; a selectable number of microseconds, but this works for now. -; -; If you know a better way to do 2us delay, pleae tell me! -;*************************************************************************** -delay_us: - push eax - push ecx - - mov ecx,2 - - in al,0x61 - and al,0x10 - mov ah,al - cld - -dcnt1: - in al,0x61 - and al,0x10 - cmp al,ah - jz dcnt1 - - mov ah,al - loop dcnt1 - - pop ecx - pop eax - - ret - -;*************************************************************************** -; Function -; scan_bus -; -; Description -; Scans the PCI bus for a supported device -; If a supported device is found, the drvr_ variables are initialised -; to that drivers functions ( as defined in the PCICards table) -; -; io_addr holds card I/O space. 32 bit, but only LS 16 bits valid -; pci_data holds the PCI vendor + device code -; pci_dev holds PCI bus dev # -; pci_bus holds PCI bus # -; -; io_addr will be zero if no card found -; -;*************************************************************************** -scan_bus: - xor eax, eax - mov [hdrtype], al - mov [pci_data], eax - - xor ebx, ebx ; ebx = bus# 0 .. 255 - -sb_bus_loop: - xor ecx, ecx ; ecx = devfn# 0 .. 254 ( not 255? ) - -sb_devf_loop: - mov eax, ecx - and eax, 0x07 - - cmp eax, 0 - jne sb_001 - - mov edx, PCI_HEADER_TYPE - call pcibios_read_config_byte - mov [hdrtype], al - jmp sb_002 - -sb_001: - mov al, [hdrtype] - and al, 0x80 - cmp al, 0x80 - jne sb_inc_devf - -sb_002: - mov edx, PCI_VENDOR_ID - call pcibios_read_config_dword - mov [vendor_device], eax - cmp eax, 0xffffffff - je sb_empty - cmp eax, 0 - jne sb_check_vendor - -sb_empty: - mov [hdrtype], byte 0 - jmp sb_inc_devf - -sb_check_vendor: - ; iterate though PCICards until end or match found - mov esi, PCICards - -sb_check: - cmp [esi], dword 0 - je sb_inc_devf ; Quit if at last entry - cmp eax, [esi] - je sb_got_card - add esi, PCICARDS_ENTRY_SIZE - jmp sb_check - -sb_got_card: - ; indicate that we have found the card - mov [pci_data], eax - mov [pci_dev], ecx - mov [pci_bus], ebx - - ; Define the driver functions - push eax - mov eax, [esi+4] - mov [drvr_probe], eax - mov eax, [esi+8] - mov [drvr_reset], eax - mov eax, [esi+12] - mov [drvr_poll], eax - mov eax, [esi+16] - mov [drvr_transmit], eax - pop eax - - mov edx, PCI_BASE_ADDRESS_0 - -sb_reg_check: - call pcibios_read_config_dword - mov [io_addr], eax - and eax, PCI_BASE_ADDRESS_IO_MASK - cmp eax, 0 - je sb_inc_reg - mov eax, [io_addr] - and eax, PCI_BASE_ADDRESS_SPACE_IO - cmp eax, 0 - je sb_inc_reg - - mov eax, [io_addr] - and eax, PCI_BASE_ADDRESS_IO_MASK - mov [io_addr], eax - -sb_exit1: - ret - -sb_inc_reg: - add edx, 4 - cmp edx, PCI_BASE_ADDRESS_5 - jbe sb_reg_check - -sb_inc_devf: - inc ecx - cmp ecx, 255 - jb sb_devf_loop - inc ebx - cmp ebx, 256 - jb sb_bus_loop - - ; We get here if we didn't find our card - ; set io_addr to 0 as an indication - xor eax, eax - mov [io_addr], eax - -sb_exit2: - ret - -;*************************************************************************** -; -; DEBUGGING CODE FOLLOWS -; -; If debugging data output is not required, ALL code & data below may -; be removed. -; -;*************************************************************************** - -if DEBUGGING_STATE = DEBUGGING_ENABLED - -;*************************************************************************** -; Function -; eth_dump -; -; Description -; Dumps a tx or rx ethernet packet over the rs232 link -; This is a debugging routine that seriously slows down the stack. -; Use with caution. -; -; Baud rate is 57600, 8n1 com1 -; eax : type (0 == rx, 1 == tx ) -; cx : # of bytes in buffer -; esi : address of buffer start -; edi : pointer to MACAddress ( tx only ) -; -;*************************************************************************** -eth_dump: - pusha - - ; Set the port to the desired speed - mov ebx, 0x3f8 ; combase - - mov edx, ebx - add edx, 3 ; data format register - mov al, 0x80 ; enable access to divisor latch - out dx, al - - mov edx, ebx - add edx, 1 ; interrupt enable register - mov al, 0x00 ; No interruts enabled - out dx, al - - mov edx, ebx - mov al, 0x20 / 16 ; set baud rate to 57600 0x10 =115200 - out dx, al - - mov edx, ebx - add edx, 3 ; data format register - mov al, 0x03 ; 8 data bits - out dx, al - - mov edx, ebx - add edx, 4 ; Modem control register - mov al, 0x08 ; out2 enabled. No handshaking. - out dx, al - - mov edx, ebx - add edx, 1 ; interrupt enable register - mov al, 0x01 ; Receive data interrupt enabled, - out dx, al - - popa - - ; First, display the type of the buffer. - ; If it is a tx buffer, display the macaddress - - pusha - - cmp eax, 0 - jne dd001 - - mov bl, 0x0a - call tx_byted - mov bl, 0x0d - call tx_byted - - ; Output "RX:" - mov bl, 'R' - call tx_byted - mov bl, 'X' - call tx_byted - mov bl, ':' - call tx_byted - jmp dump_data - -dd001: - mov bl, 0x0a - call tx_byted - mov bl, 0x0d - call tx_byted - - ; Output TX: xxxxxxxxxxxx - mov bl, 'T' - call tx_byted - mov bl, 'X' - call tx_byted - mov bl, ':' - call tx_byted - mov bl, ' ' - call tx_byted - - ; Display MAC address - xor eax, eax - mov al, [edi] - shr al, 4 - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - xor eax, eax - mov al, [edi] - and al, 0x0f - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - inc edi - xor eax, eax - mov al, [edi] - shr al, 4 - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - xor eax, eax - mov al, [edi] - and al, 0x0f - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - inc edi - xor eax, eax - mov al, [edi] - shr al, 4 - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - xor eax, eax - mov al, [edi] - and al, 0x0f - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - inc edi - xor eax, eax - mov al, [edi] - shr al, 4 - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - xor eax, eax - mov al, [edi] - and al, 0x0f - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - inc edi - xor eax, eax - mov al, [edi] - shr al, 4 - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - xor eax, eax - mov al, [edi] - and al, 0x0f - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - inc edi - xor eax, eax - mov al, [edi] - shr al, 4 - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - xor eax, eax - mov al, [edi] - and al, 0x0f - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - -dump_data: - popa - - ; OK, we come in here with - ; cx == number of byte to send - ; esi == buffer start - ; -dd_000: - mov bl, 0x0a - call tx_byted - mov bl, 0x0d - call tx_byted - - mov eax, 16 ; Number of characters on the line - mov edi, esi ; Save first byte position for later - - push ecx - -dd_001: - push eax - - ; Print a byte, and a space - xor eax, eax - mov al, [esi] - shr al, 4 - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - xor eax, eax - mov al, [esi] - and al, 0x0f - mov bl, [eax + hexchars] - call tx_byted ; byte in bl eax ebx edx destroyed - - mov bl, ' ' - call tx_byted - - pop eax - - inc esi - dec ecx - cmp ecx, 0 - je dd_0011 ; Print the ASCII format - - dec eax - - cmp eax, 0 - je dd_002 ; Print the ASCII format - jmp dd_001 ; Print rest of line - -dd_0011: - ; First, complete the 16 bytes of data, by printing spaces - dec eax - cmp eax, 0 - je dd_002 - - push eax - mov bl, ' ' - call tx_byted - mov bl, ' ' - call tx_byted - mov bl, ' ' - call tx_byted - pop eax - jmp dd_0011 - -dd_002: - pop ecx - mov esi, edi ; Go back to the start of the line data - - mov eax, 16 - -outLineAscii: - push eax - - xor eax, eax - mov al, [esi] - mov bl, '.' - - cmp al, 0x1F - jle outAscii - cmp al, 0x7e - jge outAscii - - mov bl, al - -outAscii: - call tx_byted ; byte in bl eax ebx edx destroyed - - pop eax - dec ecx - inc esi - cmp ecx, 0 - je dd_003 - - dec eax - cmp eax, 0 - je dd_003 - jmp outLineAscii - -dd_003: - cmp ecx, 0 - je dd_004 - jmp dd_000 - -dd_004: - ret - -;*************************************************************************** -; Function -; tx_byte -; -; Description -; Send a byte in bl out of the com port 1 -; destroys eax, edx -; -;*************************************************************************** -tx_byted: - push ebx ; Save the byte - - mov ebx, 0x3f8 ; get the com port address - - ; Wait for transmit buffer to empty. This could take 1ms @ 9600baud - - mov edx, ebx - add edx, 5 - -wait_txd: - in al, dx ; read uart serialisation status - and al, 0x40 - cmp al, 0 - jz wait_txd ; loop until free - - mov edx, ebx - pop eax ; restore the byte to send - out dx, al - ret - -iglobal - ; This is used for translating hex to ASCII for display or output - hexchars db '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' -endg -end if - + .exit: + ret \ No newline at end of file diff --git a/kernel/trunk/network/eth_drv/pci.inc b/kernel/trunk/network/eth_drv/pci.inc new file mode 100644 index 0000000000..d928e58d22 --- /dev/null +++ b/kernel/trunk/network/eth_drv/pci.inc @@ -0,0 +1,339 @@ +;*************************************************************************** +; +; PCI CODE FOLLOWS +; +; the following functions provide access to the PCI interface. +; These functions are used by scan_bus, and also some ethernet drivers +; +;*************************************************************************** + +; PCI Bus defines +PCI_HEADER_TYPE equ 0x0e ;8 bit +PCI_BASE_ADDRESS_0 equ 0x10 ;32 bit +PCI_BASE_ADDRESS_5 equ 0x24 ;32 bits +PCI_BASE_ADDRESS_SPACE_IO equ 0x01 +PCI_VENDOR_ID equ 0x00 ;16 bit +PCI_BASE_ADDRESS_IO_MASK equ 0xFFFFFFFC + +;*************************************************************************** +; Function +; config_cmd +; +; Description +; creates a command dword for use with the PCI bus +; bus # in ebx +; devfn in ecx +; where in edx +; +; command dword returned in eax +; Only eax destroyed +;*************************************************************************** +config_cmd: + push ecx + mov eax, ebx + shl eax, 16 + or eax, 0x80000000 + shl ecx, 8 + or eax, ecx + pop ecx + or eax, edx + and eax, 0xFFFFFFFC + ret + +;*************************************************************************** +; Function +; pcibios_read_config_byte +; +; Description +; reads a byte from the PCI config space +; bus # in ebx +; devfn in ecx +; where in edx ( ls 16 bits significant ) +; +; byte returned in al ( rest of eax zero ) +; Only eax/edx destroyed +;*************************************************************************** +pcibios_read_config_byte: + call config_cmd + push dx + mov dx, 0xCF8 + out dx, eax + pop dx + + xor eax, eax + and dx, 0x03 + add dx, 0xCFC +; and dx, 0xFFC + in al, dx + ret + +;*************************************************************************** +; Function +; pcibios_read_config_word +; +; Description +; reads a word from the PCI config space +; bus # in ebx +; devfn in ecx +; where in edx ( ls 16 bits significant ) +; +; word returned in ax ( rest of eax zero ) +; Only eax/edx destroyed +;*************************************************************************** +pcibios_read_config_word: + call config_cmd + push dx + mov dx, 0xCF8 + out dx, eax + pop dx + + xor eax, eax + and dx, 0x02 + add dx, 0xCFC +; and dx, 0xFFC + in ax, dx + ret + +;*************************************************************************** +; Function +; pcibios_read_config_dword +; +; Description +; reads a dword from the PCI config space +; bus # in ebx +; devfn in ecx +; where in edx ( ls 16 bits significant ) +; +; dword returned in eax +; Only eax/edx destroyed +;*************************************************************************** +pcibios_read_config_dword: + push edx + call config_cmd + push dx + mov dx, 0xCF8 + out dx, eax + pop dx + xor eax, eax + mov dx, 0xCFC + in eax, dx + pop edx + ret + +;*************************************************************************** +; Function +; pcibios_write_config_byte +; +; Description +; write a byte in al to the PCI config space +; bus # in ebx +; devfn in ecx +; where in edx ( ls 16 bits significant ) +; +; Only eax/edx destroyed +;*************************************************************************** +pcibios_write_config_byte: + push ax + call config_cmd + push dx + mov dx, 0xCF8 + out dx, eax + pop dx + pop ax + + and dx, 0x03 + add dx, 0xCFC + out dx, al + ret + +;*************************************************************************** +; Function +; pcibios_write_config_word +; +; Description +; write a word in ax to the PCI config space +; bus # in ebx +; devfn in ecx +; where in edx ( ls 16 bits significant ) +; +; Only eax/edx destroyed +;*************************************************************************** +pcibios_write_config_word: + push ax + call config_cmd + push dx + mov dx, 0xCF8 + out dx, eax + pop dx + pop ax + + and dx, 0x02 + add dx, 0xCFC + out dx, ax + ret + +;*************************************************************************** +; Function +; delay_us +; +; Description +; delays for 30 to 60 us +; +; I would prefer this routine to be able to delay for +; a selectable number of microseconds, but this works for now. +; +; If you know a better way to do 2us delay, pleae tell me! +;*************************************************************************** +delay_us: + push eax + push ecx + + mov ecx,2 + + in al,0x61 + and al,0x10 + mov ah,al + cld + +dcnt1: + in al,0x61 + and al,0x10 + cmp al,ah + jz dcnt1 + + mov ah,al + loop dcnt1 + + pop ecx + pop eax + + ret + +;*************************************************************************** +; Function +; scan_bus +; +; Description +; Scans the PCI bus for a supported device +; If a supported device is found, the drvr_ variables are initialised +; to that drivers functions ( as defined in the PCICards table) +; +; io_addr holds card I/O space. 32 bit, but only LS 16 bits valid +; pci_data holds the PCI vendor + device code +; pci_dev holds PCI bus dev # +; pci_bus holds PCI bus # +; +; io_addr will be zero if no card found +; +;*************************************************************************** +scan_bus: + xor eax, eax + mov [hdrtype], al + mov [pci_data], eax + + xor ebx, ebx ; ebx = bus# 0 .. 255 + +sb_bus_loop: + xor ecx, ecx ; ecx = devfn# 0 .. 254 ( not 255? ) + +sb_devf_loop: + mov eax, ecx + and eax, 0x07 + + cmp eax, 0 + jne sb_001 + + mov edx, PCI_HEADER_TYPE + call pcibios_read_config_byte + mov [hdrtype], al + jmp sb_002 + +sb_001: + mov al, [hdrtype] + and al, 0x80 + cmp al, 0x80 + jne sb_inc_devf + +sb_002: + mov edx, PCI_VENDOR_ID + call pcibios_read_config_dword + mov [vendor_device], eax + cmp eax, 0xffffffff + je sb_empty + cmp eax, 0 + jne sb_check_vendor + +sb_empty: + mov [hdrtype], byte 0 + jmp sb_inc_devf + +sb_check_vendor: + ; iterate though PCICards until end or match found + mov esi, PCICards + +sb_check: + cmp [esi], dword 0 + je sb_inc_devf ; Quit if at last entry + cmp eax, [esi] + je sb_got_card + add esi, PCICARDS_ENTRY_SIZE + jmp sb_check + +sb_got_card: + ; indicate that we have found the card + mov [pci_data], eax + mov [pci_dev], ecx + mov [pci_bus], ebx + + ; Define the driver functions + push eax + mov eax, [esi+4] + mov [drvr_probe], eax + mov eax, [esi+8] + mov [drvr_reset], eax + mov eax, [esi+12] + mov [drvr_poll], eax + mov eax, [esi+16] + mov [drvr_transmit], eax + pop eax + + mov edx, PCI_BASE_ADDRESS_0 + +sb_reg_check: + call pcibios_read_config_dword + mov [io_addr], eax + and eax, PCI_BASE_ADDRESS_IO_MASK + cmp eax, 0 + je sb_inc_reg + mov eax, [io_addr] + and eax, PCI_BASE_ADDRESS_SPACE_IO + cmp eax, 0 + je sb_inc_reg + + mov eax, [io_addr] + and eax, PCI_BASE_ADDRESS_IO_MASK + mov [io_addr], eax + +sb_exit1: + ret + +sb_inc_reg: + add edx, 4 + cmp edx, PCI_BASE_ADDRESS_5 + jbe sb_reg_check + +sb_inc_devf: + inc ecx + cmp ecx, 255 + jb sb_devf_loop + inc ebx + cmp ebx, 256 + jb sb_bus_loop + + ; We get here if we didn't find our card + ; set io_addr to 0 as an indication + xor eax, eax + mov [io_addr], eax + +sb_exit2: + ret \ No newline at end of file diff --git a/kernel/trunk/network/icmp.inc b/kernel/trunk/network/icmp.inc new file mode 100644 index 0000000000..cc4ad81f16 --- /dev/null +++ b/kernel/trunk/network/icmp.inc @@ -0,0 +1,188 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; ICMP.INC +;; +;; Internet Control Message Protocol ( RFC 792 ) +;; +;; Last revision: 11.11.2006 +;; +;; This file contains the following: +;; icmp_rx - processes ICMP-packets received by the IP layer +;; +;; Changes history: +;; 22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net +;; 11.11.2006 - [Johnny_B] and [smb] +;; +;; Current status: +;; This implemetation of ICMP proto supports message of ECHO type. +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +struc ICMP_PACKET +{ .Type db ? ;+00 + .Code db ? ;+01 + .Checksum dw ? ;+02 + .Identifier dw ? ;+04 + .SequenceNumber dw ? ;+06 + .Data db ? ;+08 +} + +virtual at 0 + ICMP_PACKET ICMP_PACKET +end virtual + + +; Example: +; ECHO message format +; +; +; 0 1 2 3 +; 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; | Type | Code | Checksum | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; | Identifier | Sequence Number | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; | Data ... +; +-+-+-+-+- +; + +; +; ICMP types & codes, RFC 792 and FreeBSD's ICMP sources +; + +ICMP_ECHOREPLY equ 0 ; echo reply message + +ICMP_UNREACH equ 3 + ICMP_UNREACH_NET equ 0 ; bad net + ICMP_UNREACH_HOST equ 1 ; bad host + ICMP_UNREACH_PROTOCOL equ 2 ; bad protocol + ICMP_UNREACH_PORT equ 3 ; bad port + ICMP_UNREACH_NEEDFRAG equ 4 ; IP_DF caused drop + ICMP_UNREACH_SRCFAIL equ 5 ; src route failed + ICMP_UNREACH_NET_UNKNOWN equ 6 ; unknown net + ICMP_UNREACH_HOST_UNKNOWN equ 7 ; unknown host + ICMP_UNREACH_ISOLATED equ 8 ; src host isolated + ICMP_UNREACH_NET_PROHIB equ 9 ; prohibited access + ICMP_UNREACH_HOST_PROHIB equ 10 ; ditto + ICMP_UNREACH_TOSNET equ 11 ; bad tos for net + ICMP_UNREACH_TOSHOST equ 12 ; bad tos for host + ICMP_UNREACH_FILTER_PROHIB equ 13 ; admin prohib + ICMP_UNREACH_HOST_PRECEDENCE equ 14 ; host prec vio. + ICMP_UNREACH_PRECEDENCE_CUTOFF equ 15 ; prec cutoff + +ICMP_SOURCEQUENCH equ 4 ; packet lost, slow down + +ICMP_REDIRECT equ 5 ; shorter route, codes: + ICMP_REDIRECT_NET equ 0 ; for network + ICMP_REDIRECT_HOST equ 1 ; for host + ICMP_REDIRECT_TOSNET equ 2 ; for tos and net + ICMP_REDIRECT_TOSHOST equ 3 ; for tos and host + +ICMP_ALTHOSTADDR equ 6 ; alternate host address +ICMP_ECHO equ 8 ; echo service +ICMP_ROUTERADVERT equ 9 ; router advertisement + ICMP_ROUTERADVERT_NORMAL equ 0 ; normal advertisement + ICMP_ROUTERADVERT_NOROUTE_COMMON equ 16 ; selective routing + +ICMP_ROUTERSOLICIT equ 10 ; router solicitation +ICMP_TIMXCEED equ 11 ; time exceeded, code: + ICMP_TIMXCEED_INTRANS equ 0 ; ttl==0 in transit + ICMP_TIMXCEED_REASS equ 1 ; ttl==0 in reass + +ICMP_PARAMPROB equ 12 ; ip header bad + ICMP_PARAMPROB_ERRATPTR equ 0 ; error at param ptr + ICMP_PARAMPROB_OPTABSENT equ 1 ; req. opt. absent + ICMP_PARAMPROB_LENGTH equ 2 ; bad length + +ICMP_TSTAMP equ 13 ; timestamp request +ICMP_TSTAMPREPLY equ 14 ; timestamp reply +ICMP_IREQ equ 15 ; information request +ICMP_IREQREPLY equ 16 ; information reply +ICMP_MASKREQ equ 17 ; address mask request +ICMP_MASKREPLY equ 18 ; address mask reply +ICMP_TRACEROUTE equ 30 ; traceroute +ICMP_DATACONVERR equ 31 ; data conversion error +ICMP_MOBILE_REDIRECT equ 32 ; mobile host redirect +ICMP_IPV6_WHEREAREYOU equ 33 ; IPv6 where-are-you + ICMP_IPV6_IAMHERE equ 34 ; IPv6 i-am-here +ICMP_MOBILE_REGREQUEST equ 35 ; mobile registration req +ICMP_MOBILE_REGREPLY equ 36 ; mobile registreation reply +ICMP_SKIP equ 39 ; SKIP + +ICMP_PHOTURIS equ 40 ; Photuris + ICMP_PHOTURIS_UNKNOWN_INDEX equ 1 ; unknown sec index + ICMP_PHOTURIS_AUTH_FAILED equ 2 ; auth failed + ICMP_PHOTURIS_DECRYPT_FAILED equ 3 ; decrypt failed + + +;*************************************************************************** +; Function +; icmp_rx [by Johnny_B] +; +; Description +; ICMP protocol handler +; This is a kernel function, called by ip_rx +; +; IN: +; buffer_number - # of IP-buffer. This buffer must be reused or marked as empty afterwards +; IPPacketBase - IP_PACKET base address +; IPHeaderLength - Header length of IP_PACKET +; +; OUT: +; EAX=not defined +; +; All used registers will be saved +; +;*************************************************************************** +proc icmp_rx stdcall uses ebx esi edi,\ + buffer_number:DWORD,IPPacketBase:DWORD,IPHeaderLength:DWORD + + mov esi,[IPPacketBase] ;esi=IP_PACKET base address + mov edi, esi + add edi,[IPHeaderLength] ;edi=ICMP_PACKET base address + + cmp byte[edi + ICMP_PACKET.Type], ICMP_ECHO ; Is this an echo request? discard if not + jz .icmp_echo + + mov eax, [buffer_number] + call freeBuff + jmp .exit + + .icmp_echo: + + ; swap the source and destination addresses + mov ecx, [esi + IP_PACKET.DestinationAddress] + mov ebx, [esi + IP_PACKET.SourceAddress] + mov [esi + IP_PACKET.DestinationAddress], ebx + mov [esi + IP_PACKET.SourceAddress], ecx + + ; recalculate the IP header checksum + mov eax,[IPHeaderLength] + stdcall checksum_jb,esi,eax ;buf_ptr,buf_size + + mov byte[esi + IP_PACKET.HeaderChecksum], ah + mov byte[esi + IP_PACKET.HeaderChecksum + 1], al ; ?? correct byte order? + + mov byte[edi + ICMP_PACKET.Type], ICMP_ECHOREPLY ; change the request to a response + mov word[edi + ICMP_PACKET.Checksum], 0 ; clear ICMP checksum prior to re-calc + + ; Calculate the length of the ICMP data ( IP payload) + xor eax, eax + mov ah, byte[esi + IP_PACKET.TotalLength] + mov al, byte[esi + IP_PACKET.TotalLength + 1] + sub ax, word[IPHeaderLength] ;ax=ICMP-packet length + + stdcall checksum_jb,edi,eax ;buf_ptr,buf_size + + mov byte[edi + ICMP_PACKET.Checksum], ah + mov byte[edi + ICMP_PACKET.Checksum + 1], al + + ; Queue packet for transmission + mov ebx, [buffer_number] + mov eax, NET1OUT_QUEUE + call queue + + .exit: + ret +endp \ No newline at end of file diff --git a/kernel/trunk/network/ip.inc b/kernel/trunk/network/ip.inc index 36d46cff75..38e126ce96 100644 --- a/kernel/trunk/network/ip.inc +++ b/kernel/trunk/network/ip.inc @@ -12,6 +12,29 @@ ;; ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; IP underlying protocols numbers +PROTOCOL_ICMP equ 1 +PROTOCOL_TCP equ 6 +PROTOCOL_UDP equ 17 + +struc IP_PACKET +{ .VersionAndIHL db ? ;+00 - Version[0-3 bits] and IHL(header length)[4-7 bits] + .TypeOfService db ? ;+01 + .TotalLength dw ? ;+02 + .Identification dw ? ;+04 + .FlagsAndFragmentOffset dw ? ;+06 - Flags[0-2] and FragmentOffset[3-15] + .TimeToLive db ? ;+08 + .Protocol db ? ;+09 + .HeaderChecksum dw ? ;+10 + .SourceAddress dd ? ;+12 + .DestinationAddress dd ? ;+16 + .DataOrOptional dd ? ;+20 +} + +virtual at 0 + IP_PACKET IP_PACKET +end virtual + ;******************************************************************* ; Interface @@ -24,179 +47,148 @@ ;******************************************************************* +; +; IP Packet after reception - Normal IP packet format +; +; 0 1 2 3 +; 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 +; +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +;0 |Version| IHL |Type of Service| Total Length | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +;4 | Identification |Flags| Fragment Offset | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +;8 | Time to Live | Protocol | Header Checksum | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +;12 | Source Address | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +;16 | Destination Address | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +;20 | Data | +; +-+-+-.......... -+ +; +; +; [smb] attention! according to RFC 791 IP packet may have 'options' sections, +; so we can't simply think, that data have offset 20. We must calculate offset from +; IHL field +; +macro GET_IHL reg, header_addr +{ + movzx reg, byte [header_addr] + + ; we need 4-7 bits, so.... + and reg, 0x0000000F + + ; IHL keeps number of octets, so we need to << 2 'reg' + shl reg, 2 +} + + ;*************************************************************************** ; Function ; ip_rx ; ; Description -; Handles received IP packets ; This is a kernel function, called by stack_handler +; Processes all IP-packets received by the network layer +; It calls the appropriate protocol handler ; ;*************************************************************************** -ip_rx: +proc ip_rx stdcall +local buffer_number dd ? + ; Look for a buffer to tx mov eax, IPIN_QUEUE call dequeue cmp ax, NO_BUFFER - je ipr_exit ; Exit if no buffer available + je .exit ; Exit if no buffer available - push eax + mov [buffer_number], eax ;save buffer number ; convert buffer pointer eax to the absolute address - mov ecx, IPBUFFSIZE - mul ecx + imul eax, IPBUFFSIZE add eax, IPbuffs - mov edx, eax ; Save the address in edx for use by future processes + mov ebx, eax ; ebx=pointer to IP_PACKET ; Validate the IP checksum - mov ebx, edx - mov ah, [ebx + 10] - mov al, [ebx + 11] ; Get the checksum in intel format - mov [ebx + 10], word 0 ; clear checksum field - need to when - ; recalculating checksum - + mov dx, word[ebx + IP_PACKET.HeaderChecksum] + xchg dh,dl ; Get the checksum in intel format + + mov [ebx + IP_PACKET.HeaderChecksum], word 0 ; clear checksum field - need to when + ; recalculating checksum ; this needs two data pointers and two size #. ; 2nd pointer can be of length 0 - mov ebx, edx - mov [checkAdd1], ebx - mov [checkSize1], word 20 - mov [checkAdd2], dword 0 - mov [checkSize2], word 0 - call checksum ; Recalculate IP checksum - cmp ax, [checkResult] - jnz ipr_dump + GET_IHL ecx, ebx + IP_PACKET.VersionAndIHL ;get packet length in ecx + stdcall checksum_jb, ebx, ecx ;buf_ptr, buf_size + cmp dx, ax + + mov edx, ebx ; EDX (IP-BUFFER POINTER) WILL BE USED FOR *_rx HANDLERS BELOW!!! + jnz .dump ;if CHECKSUM isn't valid then dump packet + + ; Validate the IP address, if it isn't broadcast + mov eax, [stack_ip] + cmp dword[ebx + IP_PACKET.DestinationAddress], eax + je @f ; If the IP address is 255.255.255.255, accept it ; - it is a broadcast packet, which we need for dhcp - mov eax, [edx + 16] - cmp eax, 0xffffffff - je ipr_p0 + cmp dword[ebx + IP_PACKET.DestinationAddress], 0xffffffff + jne .dump - ; Validate the IP address, if it isn't broadcast - cmp eax, [stack_ip] - jnz ipr_dump + @@: + mov al, [ebx + IP_PACKET.VersionAndIHL] + and al, 0x0f ;get IHL(header length) + cmp al, 0x05 ;if IHL!= 5*4(20 bytes) + jnz .dump ;then dump it -ipr_p0: - mov al, [edx] - and al, 0x0f - cmp al, 0x05 - jnz ipr_dump + cmp byte[ebx + IP_PACKET.TimeToLive], byte 0 + je .dump ;if TTL==0 then dump it - cmp [edx+8], byte 0 - jz ipr_dump - - mov ax, [edx + 6] - and ax, 0xFFBF - cmp ax, 0 - jnz ipr_dump + mov ax, word[ebx + IP_PACKET.FlagsAndFragmentOffset] + and ax, 0xFFBF ;get flags + cmp ax, 0 ;if some flags was set then we dump this packet + jnz .dump ;the flags should be used for fragmented packets ; Check the protocol, and call the appropriate handler ; Each handler will re-use or free the queue buffer as appropriate - mov al, [edx + 9] - cmp al , PROTOCOL_ICMP - jnz ipr_p1 - pop eax - call icmp_rx - jmp ipr_exit -ipr_p1: + mov al, [ebx + IP_PACKET.Protocol] + cmp al , PROTOCOL_TCP - jnz ipr_p2 - pop eax + jne .not_tcp + mov eax, dword[buffer_number] call tcp_rx - jmp ipr_exit + jmp .exit -ipr_p2: - cmp al , PROTOCOL_UDP - jnz ipr_dump - pop eax + .not_tcp: + cmp al, PROTOCOL_UDP + jne .not_udp + mov eax, dword[buffer_number] call udp_rx - jmp ipr_exit + jmp .exit -ipr_dump: + .not_udp: + cmp al , PROTOCOL_ICMP + jne .dump ;protocol ain't supported + + ;GET_IHL ecx, ebx + IP_PACKET.VersionAndIHL ;get packet length in ecx + mov eax, dword[buffer_number] + stdcall icmp_rx,eax,ebx,ecx ;buffer_number,IPPacketBase,IPHeaderLength + jmp .exit + + +.dump: ; No protocol handler available, so ; silently dump the packet, freeing up the queue buffer -; inc dword [dumped_rx_count] + inc dword [dumped_rx_count] - pop eax + mov eax, dword[buffer_number] call freeBuff -ipr_exit: + .exit: ret +endp - - -;*************************************************************************** -; Function -; icmp_rx -; -; Description -; ICMP protocol handler -; This is a kernel function, called by ip_rx -; edx contains the address of the buffer in use. -; This buffer must be reused or marked as empty afterwards -; -;*************************************************************************** -icmp_rx: - cmp [edx + 20], byte 8 ; Is this an echo request? discard if not - jz icmp_echo - - call freeBuff - jmp icmp_exit - -icmp_echo: - push eax - mov [edx + 10], word 0 ; I think this was already done by IP rx - - ; swap the source and destination addresses - mov ecx, [edx + 16] - mov eax, [edx + 12] - mov [edx + 16], eax - mov [edx + 12], ecx - - ; recaluculate the IP header checksum - - mov ebx, edx - mov [checkAdd1], ebx - mov [checkSize1], word 20 - mov [checkAdd2], dword 0 - mov [checkSize2], word 0 - - call checksum - mov ax, [checkResult] - mov [edx + 10], ah - mov [edx + 11], al ; ?? correct byte order? - - mov [edx + 20], byte 0 ; change the request to a response - mov [edx + 22], word 0 ; clear ICMP checksum prior to re-calc - - ; Calculate the length of the ICMP data ( IP payload) - mov ah, [edx + 2] - mov al, [edx + 3] - sub ax, 20 - - mov [checkSize1], ax - mov ebx, edx - add ebx, 20 - - mov [checkAdd1], ebx - mov [checkAdd2], dword 0 - mov [checkSize2], word 0 - - call checksum - - mov ax, [checkResult] - mov [edx + 22], ah - mov [edx + 23], al - - ; Queue packet for transmission - - pop ebx - mov eax, NET1OUT_QUEUE - call queue - -icmp_exit: - ret \ No newline at end of file diff --git a/kernel/trunk/network/socket.inc b/kernel/trunk/network/socket.inc new file mode 100644 index 0000000000..db4a6c0be8 --- /dev/null +++ b/kernel/trunk/network/socket.inc @@ -0,0 +1,863 @@ +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; +;; SOCKET.INC +;; +;; Sockets constants, structures and functions +;; +;; Last revision: 11.11.2006 +;; +;; This file contains the following: +;; is_localport_unused +;; get_free_socket +;; socket_open +;; socket_open_tcp +;; socket_close +;; socket_close_tcp +;; socket_poll +;; socket_status +;; socket_read +;; socket_write +;; socket_write_tcp +;; +;; +;; Changes history: +;; 22.09.2003 - [Mike Hibbett] : mikeh@oceanfree.net +;; 11.11.2006 - [Johnny_B] and [smb] +;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; +; Socket Descriptor + Buffer +; +; 0 1 2 3 +; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +; +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 0| Status ( of this buffer ) | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 4| Application Process ID | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 8| Local IP Address | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 12| Local IP Port | Unused ( set to 0 ) | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 16| Remote IP Address | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 20| Remote IP Port | Unused ( set to 0 ) | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 24| Rx Data Count INTEL format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 28| TCB STATE INTEL format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 32| TCB Timer (seconds) INTEL format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 36| ISS (Inital Sequence # used by this connection ) INET format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 40| IRS ( Inital Receive Sequence # ) INET format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 44| SND.UNA Seq # of unack'ed sent packets INET format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 48| SND.NXT Next send seq # to use INET format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 52| SND.WND Send window INET format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 56| RCV.NXT Next expected receive sequence # INET format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 60| RCV.WND Receive window INET format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 64| SEG.LEN Segment length INTEL format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 68| SEG.WND Segment window INTEL format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 72| Retransmit queue # NOW WINDOW SIZE TIMER INTEL format| +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; 76| RX offset from +; 76| RX Data | +; +-+-+-.......... -+ + + +; so, define struct +struc SOCKET +{ .Status dd ? ;+00 - Status ( of this buffer ) + .PID dd ? ;+04 - Application Process ID + .LocalIP dd ? ;+08 - Local IP Address + .LocalPort dw ? ;+12 - Local Port + .UnusedL dw ? ;+14 - may be removed in future + .RemoteIP dd ? ;+16 - Remote IP Address + .RemotePort dw ? ;+20 - Remote Port + .UnusedR dw ? ;+22 - may be removed in future + .rxDataCount dd ? ;+24 - Rx Data Count + .TCBState dd ? ;+28 - TCB STATE + .TCBTimer dd ? ;+32 - TCB Timer (seconds) + .ISS dd ? ;+36 - Initial Send Sequence + .IRS dd ? ;+40 - Initial Receive Sequence + .SND_UNA dd ? ;+44 - Sequence number of unack'ed sent packets + .SND_NXT dd ? ;+48 - Next send sequence number to use + .SND_WND dd ? ;+52 - Send window + .RCV_NXT dd ? ;+56 - Next receive sequence number to use + .RCV_WND dd ? ;+60 - Receive window + .SEG_LEN dd ? ;+64 - Segment length + .SEG_WND dd ? ;+68 - Segment window + .wndsizeTimer dd ? ;+72 - Retransmit queue # NOW WINDOW SIZE TIMER + .rxData dd ? ;+76 - receive data buffer here +} + +virtual at 0 + SOCKET SOCKET +end virtual + +; simple macro calcing real memory address of SOCKET struct by socket's +macro Index2RealAddr reg +{ + shl reg, 12 + add reg, sockets +} + +;Constants +; current socket statuses +SOCK_EMPTY equ 0 ; socket not in use +SOCK_OPEN equ 1 ; open issued, but no data sent + +; TCP opening modes +SOCKET_PASSIVE equ 0 +SOCKET_ACTIVE equ 1 + +;*************************************************************************** +; Function +; is_localport_unused +; +; Description +; scans through all the active sockets , looking to see if the +; port number specified in bx is in use as a localport number. +; This is useful when you want a to generate a unique local port +; number. +; On return, eax = 1 for free, 0 for in use +; +;*************************************************************************** +is_localport_unused: + mov al, bh + mov ah, bl + mov bx, ax + + mov edx, SOCKETBUFFSIZE * NUM_SOCKETS + mov ecx, NUM_SOCKETS + mov eax, 0 ; Assume the return value is 'in use' + +ilu1: + sub edx, SOCKETBUFFSIZE + cmp [edx + sockets + SOCKET.LocalPort], bx + loopnz ilu1 ; Return back if the socket is occupied + + jz ilu_exit + inc eax ; return port not in use + +ilu_exit: + ret + + + +;*************************************************************************** +; Function +; get_free_socket +; +; Description +; +;*************************************************************************** +get_free_socket: + push ecx + mov eax, SOCKETBUFFSIZE * NUM_SOCKETS + mov ecx, NUM_SOCKETS + +gfs1: + sub eax, SOCKETBUFFSIZE + cmp [eax + sockets + SOCKET.Status], dword SOCK_EMPTY + loopnz gfs1 ; Return back if the socket is occupied + mov eax, ecx + pop ecx + jz gfs_exit + mov eax, 0xFFFFFFFF + +gfs_exit: + ret + + +;*************************************************************************** +; Function +; socket_open +; +; Description +; find a free socket +; local port in ebx +; remote port in ecx +; remote ip in edx +; return socket # in eax, -1 if none available +; +;*************************************************************************** +socket_open: + call get_free_socket + + cmp eax, 0xFFFFFFFF + jz so_exit + + ; ax holds the socket number that is free. Get real address + push eax + Index2RealAddr eax + + mov [eax + SOCKET.Status], dword SOCK_OPEN + + xchg bh, bl + mov [eax + SOCKET.LocalPort], bx +; mov [eax + 12], byte bh ; Local port ( LS 16 bits ) +; mov [eax + 13], byte bl ; Local port ( LS 16 bits ) + xchg ch, cl + mov [eax + SOCKET.RemotePort], cx +; mov [eax + 20], ch ; Remote Port ( LS 16 bits ) +; mov [eax + 21], cl ; Remote Port ( LS 16 bits ) + + mov ebx, [stack_ip] + mov [eax + SOCKET.LocalIP], ebx + mov [eax + SOCKET.RemoteIP], edx + mov [eax + SOCKET.rxDataCount], dword 0 ; recieved data count + + mov esi, [0x3010] + mov ebx, [esi+TASKDATA.pid] + mov [eax + SOCKET.PID], ebx ; save the process ID + pop eax ; Get the socket number back, so we can return it + +so_exit: + ret + + + +;*************************************************************************** +; Function +; socket_open_tcp +; +; Description +; Opens a TCP socket in PASSIVE or ACTIVE mode +; find a free socket +; local port in ebx ( intel format ) +; remote port in ecx ( intel format ) +; remote ip in edx ( in Internet byte order ) +; Socket open mode in esi ( SOCKET_PASSIVE or SOCKET_ACTIVE ) +; return socket # in eax, -1 if none available +; +;*************************************************************************** +socket_open_tcp: + call get_free_socket + + cmp eax, 0xFFFFFFFF + jz so_exit + + ; ax holds the socket number that is free. Get real address + push eax + Index2RealAddr eax + + mov [sktAddr], eax + mov [eax], dword SOCK_OPEN + + ; TODO - check this works! + mov [eax + SOCKET.wndsizeTimer], dword 0 ; Reset the window timer. + + xchg bh, bl + mov [eax + SOCKET.LocalPort], bx +; mov [eax + 12], byte bh ; Local port ( LS 16 bits ) +; mov [eax + 13], byte bl ; Local port ( LS 16 bits ) + + xchg ch, cl + mov [eax + SOCKET.RemotePort], cx +; mov [eax + 20], ch ; Remote Port ( LS 16 bits ) +; mov [eax + 21], cl ; Remote Port ( LS 16 bits ) + + mov ebx, [stack_ip] + mov [eax + SOCKET.LocalIP], ebx + mov [eax + SOCKET.RemoteIP], edx + mov [eax + SOCKET.rxDataCount], dword 0 + + ; Now fill in TCB state + mov ebx, TCB_LISTEN + cmp esi, SOCKET_PASSIVE + jz sot_001 + mov ebx, TCB_SYN_SENT + +sot_001: + mov [eax + SOCKET.TCBState], ebx ; Indicate the state of the TCB + + mov esi, [0x3010] + mov ecx, [esi+TASKDATA.pid] + mov [eax + SOCKET.PID], ecx ; save the process ID + + cmp ebx, TCB_LISTEN + je sot_done + + ; Now, if we are in active mode, then we have to send a SYN to the specified remote port + mov eax, EMPTY_QUEUE + call dequeue + cmp ax, NO_BUFFER + je sot_done + + push eax + + mov bl, 0x02 ; SYN + mov ecx, 0 + + call buildTCPPacket + + mov eax, NET1OUT_QUEUE + + mov edx, [stack_ip] + mov ecx, [sktAddr ] + mov ecx, [ecx + 16] + cmp edx, ecx + jne sot_notlocal + mov eax, IPIN_QUEUE + +sot_notlocal: + ; Send it. + pop ebx + call queue + + mov esi, [sktAddr] + + ; increment SND.NXT in socket + add esi, 48 + call inc_inet_esi + +sot_done: + pop eax ; Get the socket number back, so we can return it + +sot_exit: + ret + + + +;*************************************************************************** +; Function +; socket_close +; +; Description +; socket # in ebx +; returns 0 for ok, -1 for socket not open (fail) +; +;*************************************************************************** +socket_close: + Index2RealAddr ebx + mov eax, 0xFFFFFFFF ; assume this operation will fail.. + cmp [ebx + SOCKET.Status], dword SOCK_EMPTY + jz sc_exit + + ; Clear the socket varaibles + xor eax, eax + mov edi, ebx + mov ecx, SOCKETHEADERSIZE + cld + rep stosb + +sc_exit: + ret + + + +;*************************************************************************** +; Function +; socket_close_tcp +; +; Description +; socket # in ebx +; returns 0 for ok, -1 for socket not open (fail) +; +;*************************************************************************** +socket_close_tcp: + ; first, remove any resend entries + pusha + + mov esi, resendQ + mov ecx, 0 + +sct001: + cmp ecx, NUMRESENDENTRIES + je sct003 ; None left + cmp [esi], bl + je sct002 ; found one + inc ecx + add esi, 4 + jmp sct001 + +sct002: + + mov [esi], byte 0xFF + jmp sct001 + +sct003: + popa + + Index2RealAddr ebx + mov [sktAddr], ebx + mov eax, 0xFFFFFFFF ; assume this operation will fail.. + cmp [ebx + SOCKET.Status], dword SOCK_EMPTY + jz sct_exit + + ; Now construct the response, and queue for sending by IP + mov eax, EMPTY_QUEUE + call dequeue + cmp ax, NO_BUFFER + je stl_exit + + push eax + + mov bl, 0x11 ; FIN + ACK + mov ecx, 0 + mov esi, 0 + + call buildTCPPacket + + mov ebx, [sktAddr] + + ; increament SND.NXT in socket + mov esi, 48 + add esi, ebx + call inc_inet_esi + + + ; Get the socket state + mov eax, [ebx + SOCKET.TCBState] + cmp eax, TCB_LISTEN + je destroyTCB + cmp eax, TCB_SYN_SENT + je destroyTCB + cmp eax, TCB_SYN_RECEIVED + je sct_finwait1 + cmp eax, TCB_ESTABLISHED + je sct_finwait1 + + ; assume CLOSE WAIT + ; Send a fin, then enter last-ack state + mov eax, TCB_LAST_ACK + mov [ebx + SOCKET.TCBState], eax + xor eax, eax + jmp sct_send + +sct_finwait1: + ; Send a fin, then enter finwait2 state + mov eax, TCB_FIN_WAIT_1 + mov [ebx + SOCKET.TCBState], eax + xor eax, eax + +sct_send: + mov eax, NET1OUT_QUEUE + + mov edx, [stack_ip] + mov ecx, [sktAddr ] + mov ecx, [ecx + 16] + cmp edx, ecx + jne sct_notlocal + mov eax, IPIN_QUEUE + +sct_notlocal: + ; Send it. + pop ebx + call queue + jmp sct_exit + +destroyTCB: + pop eax + ; Clear the socket varaibles + xor eax, eax + mov edi, ebx + mov ecx, SOCKETHEADERSIZE + cld + rep stosb + +sct_exit: + ret + + + +;*************************************************************************** +; Function +; socket_poll +; +; Description +; socket # in ebx +; returns count in eax. +; +;*************************************************************************** +socket_poll: + Index2RealAddr ebx + mov eax, [ebx + SOCKET.rxDataCount] + + ret + + + +;*************************************************************************** +; Function +; socket_status +; +; Description +; socket # in ebx +; returns TCB state in eax. +; +;*************************************************************************** +socket_status: + Index2RealAddr ebx + mov eax, [ebx + SOCKET.TCBState] + + ret + + + +;*************************************************************************** +; Function +; socket_read +; +; Description +; socket # in ebx +; returns # of bytes remaining in eax, data in bl +; +;*************************************************************************** +socket_read: + Index2RealAddr ebx + mov eax, [ebx + SOCKET.rxDataCount] ; get count of bytes + mov ecx, 1 + test eax, eax + jz sr2 + + dec eax + mov esi, ebx ; esi is address of socket + mov [ebx + SOCKET.rxDataCount], eax ; store new count + ;movzx ebx, byte [ebx + SOCKET.rxData] ; get the byte + movzx ebx, byte [ebx + SOCKETHEADERSIZE] ; get the byte + add esi, SOCKETHEADERSIZE + mov edi, esi + inc esi + + mov ecx, (SOCKETBUFFSIZE - SOCKETHEADERSIZE) / 4 + cld + rep movsd + xor ecx, ecx + +sr1: + jmp sor_exit + +sr2: + xor bl, bl + +sor_exit: + ret + + + +;*************************************************************************** +; Function +; socket_write +; +; Description +; socket in ebx +; # of bytes to write in ecx +; pointer to data in edx +; returns 0 in eax ok, -1 == failed ( invalid socket, or +; could not queue IP packet ) +; +;*************************************************************************** +socket_write: + Index2RealAddr ebx + + mov eax, 0xFFFFFFFF + ; If the socket is invalid, return with an error code + cmp [ebx], dword SOCK_EMPTY + je sw_exit + + + mov eax, EMPTY_QUEUE + call dequeue + cmp ax, NO_BUFFER + je sw_exit + + ; Save the queue entry number + push eax + + ; save the pointers to the data buffer & size + push edx + push ecx + + ; convert buffer pointer eax to the absolute address + mov ecx, IPBUFFSIZE + mul ecx + add eax, IPbuffs + + mov edx, eax + + ; So, ebx holds the socket ptr, edx holds the IPbuffer ptr + + ; Fill in the IP header ( some data is in the socket descriptor) + mov eax, [ebx + 8] + mov [edx + 12], eax ; source IP + mov eax, [ebx + 16] + mov [edx + 16], eax ; Destination IP + + mov al, 0x45 + mov [edx], al ; Version, IHL + xor al, al + mov [edx + 1], al ; Type of service + + pop eax ; Get the UDP data length + push eax + + add eax, 20 + 8 ; add IP header and UDP header lengths + mov [edx + 2], ah + mov [edx + 3], al + xor al, al + mov [edx + 4], al + mov [edx + 5], al + mov al, 0x40 + mov [edx + 6], al + xor al, al + mov [edx + 7], al + mov al, 0x20 + mov [edx + 8], al + mov al, 17 + mov [edx + 9], al + + ; Checksum left unfilled + xor ax, ax + mov [edx + 10], ax + + ; Fill in the UDP header ( some data is in the socket descriptor) + mov ax, [ebx + 12] + mov [edx + 20], ax + + mov ax, [ebx + 20] + mov [edx + 20 + 2], ax + + pop eax + push eax + + add eax, 8 + mov [edx + 20 + 4], ah + mov [edx + 20 + 5], al + + ; Checksum left unfilled + xor ax, ax + mov [edx + 20 + 6], ax + + pop ecx ; count of bytes to send + mov ebx, ecx ; need the length later + pop eax ; get callers ptr to data to send + + ; Get the address of the callers data + mov edi, [0x3010] + add edi, TASKDATA.mem_start + add eax, [edi] + mov esi, eax + + mov edi, edx + add edi, 28 + cld + rep movsb ; copy the data across + + ; we have edx as IPbuffer ptr. + ; Fill in the UDP checksum + ; First, fill in pseudoheader + mov eax, [edx + 12] + mov [pseudoHeader], eax + mov eax, [edx + 16] + mov [pseudoHeader+4], eax + mov ax, 0x1100 ; 0 + protocol + mov [pseudoHeader+8], ax + add ebx, 8 + mov eax, ebx + mov [pseudoHeader+10], ah + mov [pseudoHeader+11], al + + mov eax, pseudoHeader + mov [checkAdd1], eax + mov [checkSize1], word 12 + mov eax, edx + add eax, 20 + mov [checkAdd2], eax + mov eax, ebx + mov [checkSize2], ax ; was eax!! mjh 8/7/02 + + call checksum + + ; store it in the UDP checksum ( in the correct order! ) + mov ax, [checkResult] + + ; If the UDP checksum computes to 0, we must make it 0xffff + ; (0 is reserved for 'not used') + cmp ax, 0 + jne sw_001 + mov ax, 0xffff + +sw_001: + mov [edx + 20 + 6], ah + mov [edx + 20 + 7], al + + ; Fill in the IP header checksum + GET_IHL ecx,edx ; get IP-Header length + stdcall checksum_jb,edx,ecx ; buf_ptr, buf_size + + mov [edx + 10], ah + mov [edx + 11], al + + ; Check destination IP address. + ; If it is the local host IP, route it back to IP_RX + + pop ebx + mov eax, NET1OUT_QUEUE + + mov ecx, [ edx + 16] + mov edx, [stack_ip] + cmp edx, ecx + jne sw_notlocal + mov eax, IPIN_QUEUE + +sw_notlocal: + ; Send it. + call queue + + xor eax, eax + +sw_exit: + ret + + + +;*************************************************************************** +; Function +; socket_write_tcp +; +; Description +; socket in ebx +; # of bytes to write in ecx +; pointer to data in edx +; returns 0 in eax ok, -1 == failed ( invalid socket, or +; could not queue IP packet ) +; +;*************************************************************************** +socket_write_tcp: + Index2RealAddr ebx + + mov [sktAddr], ebx + + mov eax, 0xFFFFFFFF + ; If the socket is invalid, return with an error code + cmp [ebx], dword SOCK_EMPTY + je swt_exit + + ; If the sockets window timer is nonzero, do not queue packet + ; TODO - done + cmp [ebx + SOCKET.wndsizeTimer], dword 0 + jne swt_exit + + mov eax, EMPTY_QUEUE + call dequeue + cmp ax, NO_BUFFER + je swt_exit + + push eax + + mov bl, 0x10 ; ACK + + ; Get the address of the callers data + mov edi, [0x3010] + add edi, TASKDATA.mem_start + add edx, [edi] + mov esi, edx + + pop eax + push eax + + push ecx + call buildTCPPacket + pop ecx + + ; Check destination IP address. + ; If it is the local host IP, route it back to IP_RX + + pop ebx + push ecx + mov eax, NET1OUT_QUEUE + + mov edx, [stack_ip] + mov ecx, [sktAddr ] + mov ecx, [ecx + 16] + cmp edx, ecx + jne swt_notlocal + mov eax, IPIN_QUEUE + +swt_notlocal: + pop ecx + + push ebx ; save ipbuffer number + + call queue + + mov esi, [sktAddr] + + ; increament SND.NXT in socket + ; Amount to increment by is in ecx + add esi, 48 + call add_inet_esi + + pop ebx + + ; Copy the IP buffer to a resend queue + ; If there isn't one, dont worry about it for now + mov esi, resendQ + mov ecx, 0 + +swt003: + cmp ecx, NUMRESENDENTRIES + je swt001 ; None found + cmp [esi], byte 0xFF + je swt002 ; found one + inc ecx + add esi, 4 + jmp swt003 + +swt002: + push ebx + + ; OK, we have a buffer descriptor ptr in esi. + ; resend entry # in ecx + ; Populate it + ; socket # + ; retries count + ; retry time + ; fill IP buffer associated with this descriptor + + mov eax, [sktAddr] + sub eax, sockets + shr eax, 12 ; get skt # + mov [esi], al + mov [esi + 1], byte TCP_RETRIES + mov [esi + 2], word TCP_TIMEOUT + + inc ecx + ; Now get buffer location, and copy buffer across. argh! more copying,, + mov edi, resendBuffer - IPBUFFSIZE +swt002a: + add edi, IPBUFFSIZE + loop swt002a + + ; we have dest buffer location in edi + pop eax + ; convert source buffer pointer eax to the absolute address + mov ecx, IPBUFFSIZE + mul ecx + add eax, IPbuffs + mov esi, eax + + ; do copy + mov ecx, IPBUFFSIZE + cld + rep movsb + +swt001: + xor eax, eax + +swt_exit: + ret + diff --git a/kernel/trunk/network/stack.inc b/kernel/trunk/network/stack.inc index 2d0427d1f3..987bb0a4da 100644 --- a/kernel/trunk/network/stack.inc +++ b/kernel/trunk/network/stack.inc @@ -16,6 +16,7 @@ ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + ;******************************************************************* ; Interface ; The interfaces defined in ETHERNET.INC plus: @@ -27,152 +28,14 @@ ; ;******************************************************************* - - -; -; IP Packet after reception - Normal IP packet format -; -; 0 1 2 3 -; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -; -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;0 |Version| IHL |Type of Service| Total Length | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;4 | Identification |Flags| Fragment Offset | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;8 | Time to Live | Protocol | Header Checksum | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;12 | Source Address | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;16 | Destination Address | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Data | -; +-+-+-.......... -+ - - -; TCP Payload ( Data field in IP datagram ) -; -; 0 1 2 3 -; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;20 | Source Port | Destination Port | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;24 | Sequence Number | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;28 | Acknowledgment Number | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;32 | Data | |U|A|P|R|S|F| | -; | Offset| Reserved |R|C|S|S|Y|I| Window | -; | | |G|K|H|T|N|N| | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;36 | Checksum | Urgent Pointer | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -;40 | Options | Padding | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | data - - -; -; UDP Payload ( Data field in IP datagram ) -; -; 0 1 2 3 -; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -; -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Source Port | Destination Port | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Length ( UDP Header + Data ) | Checksum | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | UDP Data | -; +-+-+-.......... -+ -; - - -; -; Socket Descriptor + Buffer -; -; 0 1 2 3 -; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 -; -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Status ( of this buffer ) | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Application Process ID | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Local IP Address | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Local IP Port | Unused ( set to 0 ) | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Remote IP Address | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; | Remote IP Port | Unused ( set to 0 ) | -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 24| Rx Data Count INTEL format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 28| TCB STATE INTEL format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 32| TCB Timer (seconds) INTEL format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 36| ISS (Inital Sequence # used by this connection ) INET format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 40| IRS ( Inital Receive Sequence # ) INET format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 44| SND.UNA Seq # of unack'ed sent packets INET format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 48| SND.NXT Next send seq # to use INET format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 52| SND.WND Send window INET format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 56| RCV.NXT Next expected receive sequence # INET format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 60| RCV.WND Receive window INET format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 64| SEG.LEN Segment length INTEL format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 68| SEG.WND Segment window INTEL format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 72| Retransmit queue # NOW WINDOW SIZE TIMER INTEL format| -; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ -; 76| RX Data | -; +-+-+-.......... -+ - - - -; IP protocol numbers -PROTOCOL_ICMP equ 1 -PROTOCOL_TCP equ 6 -PROTOCOL_UDP equ 17 - - -; TIPBUFF status values -BUFF_EMPTY equ 0 -BUFF_RX_FULL equ 1 -BUFF_ALLOCATED equ 2 -BUFF_TX_FULL equ 3 - -NUM_IPBUFFERS equ 20 ; buffers allocated for TX/RX - -SOCK_EMPTY equ 0 ; socket not in use -SOCK_OPEN equ 1 ; open issued, but no data sent - -; TCP opening modes -SOCKET_PASSIVE equ 0 -SOCKET_ACTIVE equ 1 - -; TCP TCB states -TCB_LISTEN equ 1 -TCB_SYN_SENT equ 2 -TCB_SYN_RECEIVED equ 3 -TCB_ESTABLISHED equ 4 -TCB_FIN_WAIT_1 equ 5 -TCB_FIN_WAIT_2 equ 6 -TCB_CLOSE_WAIT equ 7 -TCB_CLOSING equ 8 -TCB_LAST_ACK equ 9 -TCB_TIME_WAIT equ 10 -TCB_CLOSED equ 11 - -TWOMSL equ 10 ; # of secs to wait before closing socket +uglobal +StackCounters: + dumped_rx_count: dd 0 + arp_tx_count: dd 0 + arp_rx_count: dd 0 + ip_rx_count: dd 0 + ip_tx_count: dd 0 +endg ; socket buffers SOCKETBUFFSIZE equ 4096 ; state + config + buffer. @@ -180,6 +43,13 @@ SOCKETHEADERSIZE equ 76 ; thus 4096 - SOCKETHEADERSIZE bytes data NUM_SOCKETS equ 16 ; Number of open sockets supported. Was 20 +; IPBUFF status values +BUFF_EMPTY equ 0 +BUFF_RX_FULL equ 1 +BUFF_ALLOCATED equ 2 +BUFF_TX_FULL equ 3 + +NUM_IPBUFFERS equ 20 ; buffers allocated for TX/RX NUMQUEUES equ 4 EMPTY_QUEUE equ 0 @@ -191,8 +61,6 @@ NO_BUFFER equ 0xFFFF IPBUFFSIZE equ 1500 ; MTU of an ethernet packet NUMQUEUEENTRIES equ NUM_IPBUFFERS NUMRESENDENTRIES equ 18 ; Buffers for TCP resend packets -TCP_RETRIES equ 5 ; Number of times to resend a packet -TCP_TIMEOUT equ 10 ; resend if not replied to in x hs ; These are the 0x40 function codes for application access to the stack STACK_DRIVER_STATUS equ 52 @@ -208,27 +76,16 @@ stack_data_end equ 0x71ffff ; 32 bit word stack_config equ stack_data + ; 32 bit word - IP Address in network format stack_ip equ stack_data + 4 -; 1 byte. 0 == inactive, 1 = active -slip_active equ stack_data + 8 ; no longer used + ; 1 byte. 0 == inactive, 1 = active ethernet_active equ stack_data + 9 -unused equ stack_data + 10 -; word. Buffer number, -1 if none -rx_buff_ptr equ stack_data + 12 -; dword. Buffer number, -1 if none -tx_buff_ptr equ stack_data + 16 -; byte. -slip_rx_state equ stack_data + 20 ; no longer used -; byte -slip_tx_state equ stack_data + 21 ; no longer used -; dword. Index into data -rx_data_ptr equ stack_data + 22 -; dword. Index into data -tx_data_ptr equ stack_data + 26 -; word. Count of bytes to send -tx_msg_len equ stack_data + 30 + + +; TODO :: empty memory area + ; Address of selected socket sktAddr equ stack_data + 32 ; Parameter to checksum routine - data ptr @@ -250,8 +107,8 @@ sockets equ stack_data + 62 Next_free2 equ sockets + (SOCKETBUFFSIZE * NUM_SOCKETS) ; 1560 byte buffer for rx / tx ethernet packets Ether_buffer equ Next_free2 -Next_free3 equ Ether_buffer + 1560 -last_1sTick equ Next_free3 +Next_free3 equ Ether_buffer + 1518 +last_1sTick equ Next_free3 IPbuffs equ Next_free3 + 1 queues equ IPbuffs + ( NUM_IPBUFFERS * IPBUFFSIZE ) queueList equ queues + (2 * NUMQUEUES) @@ -267,6 +124,31 @@ resendQ equ 0x770000 resendBuffer equ resendQ + ( 4 * NUMRESENDENTRIES ) ; for TCP +; simple macro for memory set operation +macro _memset_dw adr,value,amount +{ + mov edi, adr + mov ecx, amount + if value = 0 + xor eax, eax + else + mov eax, value + end if + cld + rep stosd +} + + +; Below, the main network layer source code is included +; +include "queue.inc" +include "eth_drv/ethernet.inc" +include "ip.inc" +include "icmp.inc" +include "tcp.inc" +include "udp.inc" +include "socket.inc" + ;*************************************************************************** ; Function ; stack_init @@ -278,41 +160,21 @@ resendBuffer equ resendQ + ( 4 * NUMRESENDENTRIES ) ; for TCP ; in set_variables ; ;*************************************************************************** + stack_init: - xor eax,eax - mov edi,stack_data_start - mov ecx,0x20000 / 4 ; Assume that we have 128KB of data - cld - rep stosd + ; Init two address spaces with default values + _memset_dw stack_data_start, 0, 0x20000/4 + _memset_dw resendQ, 0xFFFFFFFF, NUMRESENDENTRIES - ; Initialise TCP resend queue data structures - mov eax, 0xFFFFFFFF - mov edi, resendQ - mov ecx, NUMRESENDENTRIES ; 1 dword per entry - cld - rep stosd + ; Queries initialization + call queueInit - - mov eax, 0xFFFFFFFF - mov [rx_buff_ptr], eax - mov [tx_buff_ptr], eax - - ; Put in some defaults : slip, 0x3f8, 4, ip=192.168.1.22 - ; Saves me entering them each boot up when debugging - mov eax, 0x03f80401 - mov [stack_config], eax - mov eax, 0xc801a8c0 - mov [stack_ip], eax - - call queueInit - - ; The following block sets up the 1s timer - mov al,0x0 - out 0x70,al - in al,0x71 - mov [last_1sTick], al - - ret + ; The following block sets up the 1s timer + mov al, 0x0 + out 0x70, al + in al, 0x71 + mov [last_1sTick], al +ret @@ -342,82 +204,55 @@ stack_handler: sh_001: ; Test for 1 second event, call 1s timer functions - mov al,0x0 ;second - out 0x70,al - in al,0x71 + mov al, 0x0 ;second + out 0x70, al + in al, 0x71 cmp al, [last_1sTick] je sh_exit mov [last_1sTick], al - call arp_timer + stdcall arp_table_manager, ARP_TABLE_TIMER, 0, 0 call tcp_tcb_handler sh_exit: ret +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Checksum [by Johnny_B] +;; IN: +;; buf_ptr=POINTER to buffer +;; buf_size=SIZE of buffer +;; OUT: +;; AX=16-bit checksum +;; Saves all used registers +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +proc checksum_jb stdcall uses ebx esi ecx,\ + buf_ptr:DWORD, buf_size:DWORD + xor eax, eax + xor ebx, ebx ;accumulator + mov esi, dword[buf_ptr] + mov ecx, dword[buf_size] + shr ecx, 1 ; ecx=ecx/2 + jnc @f ; if CF==0 then size is even number + mov bh, byte[esi + ecx*2] + @@: + cld + .loop: + lodsw ;eax=word[esi],esi=esi+2 + xchg ah,al ;cause must be a net byte-order + add ebx, eax + loop .loop -;*************************************************************************** -; Function -; is_localport_unused -; -; Description -; scans through all the active sockets , looking to see if the -; port number specified in bx is in use as a localport number. -; This is useful when you want a to generate a unique local port -; number. -; On return, eax = 1 for free, 0 for in use -; -;*************************************************************************** -is_localport_unused: - mov al, bh - mov ah, bl - mov bx, ax + mov eax, ebx + shr eax, 16 + add ax, bx + not ax - mov edx, SOCKETBUFFSIZE * NUM_SOCKETS - mov ecx, NUM_SOCKETS - mov eax, 0 ; Assume the return value is 'in use' - -ilu1: - sub edx, SOCKETBUFFSIZE - cmp [edx + sockets + 12], bx - loopnz ilu1 ; Return back if the socket is occupied - - jz ilu_exit - inc eax ; return port not in use - -ilu_exit: ret - - - -;*************************************************************************** -; Function -; get_free_socket -; -; Description -; -;*************************************************************************** -get_free_socket: - push ecx - mov eax, SOCKETBUFFSIZE * NUM_SOCKETS - mov ecx, NUM_SOCKETS - -gfs1: - sub eax, SOCKETBUFFSIZE - cmp [eax + sockets], dword SOCK_EMPTY - loopnz gfs1 ; Return back if the socket is occupied - mov eax, ecx - pop ecx - jz gfs_exit - mov eax, 0xFFFFFFFF - -gfs_exit: - ret - - +endp ;*************************************************************************** ; Function @@ -430,6 +265,8 @@ gfs_exit: ; Internetworking with TCP/IP Volume II by D.E. Comer ; ;*************************************************************************** + + checksum: pusha @@ -510,14 +347,14 @@ cs_exit: ; app_stack_handler ; ; Description -; This is an application service, called by int 0x40 fn 52 +; This is an application service, called by int 0x40, function 52 ; It provides application access to the network interface layer ; ;*************************************************************************** app_stack_handler: cmp eax, 0 jnz not0 - ; Read the configuartion word + ; Read the configuration word mov eax, [stack_config] ret @@ -572,20 +409,9 @@ not2: mov [stack_ip], ebx ret +;old functions was deleted + not3: - cmp eax, 4 - jnz not4 - ; Enabled the slip driver on the comm port - ; slip removed - ret - -not4: - cmp eax, 5 - jnz not5 - ; Disable the slip driver on the comm port - ; slip removed - -not5: cmp eax, 6 jnz not6 @@ -653,15 +479,101 @@ not12: not13: cmp eax, 14 - jnz stack_driver_end + jnz not14 ; write the dns IP Address mov [dns_ip], ebx + ret + +; +not14: + cmp eax, 15 + jnz not15 + + ; in ebx we need 4 to read the last 2 bytes + cmp ebx, dword 4 + je read + + ; or we need 0 to read the first 4 bytes + cmp ebx, dword 0 + jnz param_error + + ; read MAC, returned (in mirrored byte order) in eax +read: + mov eax, [node_addr + ebx] + jmp @f + +param_error: + mov eax, -1 ; params not accepted +@@: + ret + + +; 0 -> arp_probe +; 1 -> arp_announce +; 2 -> arp_responce (not supported yet) + +not15: ; ARP stuff + cmp eax, 16 + jnz not16 + + cmp ebx, 0 + je a_probe + + cmp ebx, 1 + je a_ann ; arp announce + +; cmp ebx,2 +; jne a_resp ; arp response + + jmp param15_error + + +; arp probe, sender IP must be set to 0.0.0.0, target IP is set to address being probed +; ecx: pointer to target MAC, MAC should set to 0 by application +; edx: target IP +a_probe: + push dword [stack_ip] + + mov edx, [stack_ip] + mov [stack_ip], dword 0 + mov esi, ecx ; pointer to target MAC address + call arp_request + + pop dword [stack_ip] + jmp @f + +; arp announce, sender IP must be set to target IP +; ecx: pointer to target MAC +a_ann: + mov edx, [stack_ip] + mov esi, ecx ; pointer to target MAC address + call arp_request + jmp @f + +param15_error: + mov eax, -1 + +@@: + ret +; +; modified by [smb] + +; +; ARPTable manager interface +not16: + cmp eax, 17 + jnz stack_driver_end + + ;see "proc arp_table_manager" for more details + stdcall arp_table_manager,ebx,ecx,edx ;Opcode,Index,Extra + ret +; stack_driver_end: - ret + ret @@ -670,7 +582,7 @@ stack_driver_end: ; app_socket_handler ; ; Description -; This is an application service, called by int 0x40 +; This is an application service, called by int 0x40, function 53 ; It provides application access to stack socket services ; such as opening sockets ; @@ -1080,705 +992,3 @@ sip_err_exit: mov eax, 0xFFFFFFFF ret - - -;*************************************************************************** -; Function -; socket_open -; -; Description -; find a free socket -; local port in ebx -; remote port in ecx -; remote ip in edx -; return socket # in eax, -1 if none available -; -;*************************************************************************** -socket_open: - call get_free_socket - - cmp eax, 0xFFFFFFFF - jz so_exit - - ; ax holds the socket number that is free. Get real address - push eax - shl eax, 12 - add eax, sockets - - mov [eax], dword SOCK_OPEN - - mov [eax + 12], byte bh ; Local port ( LS 16 bits ) - mov [eax + 13], byte bl ; Local port ( LS 16 bits ) - mov ebx, [stack_ip] - mov [eax + 8], ebx ; Local IP - mov [eax + 20], ch ; Remote Port ( LS 16 bits ) - mov [eax + 21], cl ; Remote Port ( LS 16 bits ) - mov [eax + 16], edx ; Remote IP ( in Internet order ) - mov [eax + 24], dword 0 ; recieved data count - - mov esi, [0x3010] - mov ebx, [esi+TASKDATA.pid] - mov [eax + 4], ebx ; save the process ID - pop eax ; Get the socket number back, so we can return it - -so_exit: - ret - - - -;*************************************************************************** -; Function -; socket_open_tcp -; -; Description -; Opens a TCP socket in PASSIVE or ACTIVE mode -; find a free socket -; local port in ebx ( intel format ) -; remote port in ecx ( intel format ) -; remote ip in edx ( in Internet byte order ) -; Socket open mode in esi ( SOCKET_PASSIVE or SOCKET_ACTIVE ) -; return socket # in eax, -1 if none available -; -;*************************************************************************** -socket_open_tcp: - call get_free_socket - - cmp eax, 0xFFFFFFFF - jz so_exit - - ; ax holds the socket number that is free. Get real address - push eax - shl eax, 12 - add eax, sockets - - mov [sktAddr], eax - mov [eax], dword SOCK_OPEN - - ; TODO - check this works! - mov [eax + 72], dword 0 ; Reset the window timer. - - mov [eax + 12], byte bh ; Local port ( LS 16 bits ) - mov [eax + 13], byte bl ; Local port ( LS 16 bits ) - mov ebx, [stack_ip] - mov [eax + 8], ebx ; Local IP - mov [eax + 20], ch ; Remote Port ( LS 16 bits ) - mov [eax + 21], cl ; Remote Port ( LS 16 bits ) - mov [eax + 16], edx ; Remote IP ( in Internet order ) - mov [eax + 24], dword 0 ; recieved data count - - ; Now fill in TCB state - mov ebx, TCB_LISTEN - cmp esi, SOCKET_PASSIVE - jz sot_001 - mov ebx, TCB_SYN_SENT - -sot_001: - mov [eax + 28], ebx ; Indicate the state of the TCB - - mov esi, [0x3010] - mov ecx, [esi+TASKDATA.pid] - mov [eax + 4], ecx ; save the process ID - - cmp ebx, TCB_LISTEN - je sot_done - - ; Now, if we are in active mode, then we have to send a SYN to the specified remote port - - - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je sot_done - - push eax - - mov bl, 0x02 ; SYN - mov ecx, 0 - - call buildTCPPacket - - mov eax, NET1OUT_QUEUE - - mov edx, [stack_ip] - mov ecx, [ sktAddr ] - mov ecx, [ ecx + 16 ] - cmp edx, ecx - jne sot_notlocal - mov eax, IPIN_QUEUE - -sot_notlocal: - ; Send it. - pop ebx - call queue - - mov esi, [sktAddr] - - ; increment SND.NXT in socket - add esi, 48 - call inc_inet_esi - -sot_done: - pop eax ; Get the socket number back, so we can return it - -sot_exit: - ret - - - -;*************************************************************************** -; Function -; socket_close -; -; Description -; socket # in ebx -; returns 0 for ok, -1 for socket not open (fail) -; -;*************************************************************************** -socket_close: - shl ebx, 12 - add ebx, sockets - mov eax, 0xFFFFFFFF ; assume this operation will fail.. - cmp [ebx], dword SOCK_EMPTY - jz sc_exit - - ; Clear the socket varaibles - xor eax, eax - mov edi,ebx - mov ecx,SOCKETHEADERSIZE - cld - rep stosb - -sc_exit: - ret - - - -;*************************************************************************** -; Function -; socket_close_tcp -; -; Description -; socket # in ebx -; returns 0 for ok, -1 for socket not open (fail) -; -;*************************************************************************** -socket_close_tcp: - ; first, remove any resend entries - pusha - - mov esi, resendQ - mov ecx, 0 - -sct001: - cmp ecx, NUMRESENDENTRIES - je sct003 ; None left - cmp [esi], bl - je sct002 ; found one - inc ecx - add esi, 4 - jmp sct001 - -sct002: - dec dword [arp_rx_count] ; ************ TEST ONLY! - - mov [esi], byte 0xFF - jmp sct001 - -sct003: - popa - - shl ebx, 12 - add ebx, sockets - mov [sktAddr], ebx - mov eax, 0xFFFFFFFF ; assume this operation will fail.. - cmp [ebx], dword SOCK_EMPTY - jz sct_exit - - ; Now construct the response, and queue for sending by IP - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je stl_exit - - push eax - - mov bl, 0x11 ; FIN + ACK - mov ecx, 0 - mov esi, 0 - - call buildTCPPacket - - mov ebx, [sktAddr] - - ; increament SND.NXT in socket - mov esi, 48 - add esi, ebx - call inc_inet_esi - - - ; Get the socket state - mov eax, [ebx + 28] - cmp eax, TCB_LISTEN - je destroyTCB - cmp eax, TCB_SYN_SENT - je destroyTCB - cmp eax, TCB_SYN_RECEIVED - je sct_finwait1 - cmp eax, TCB_ESTABLISHED - je sct_finwait1 - - ; assume CLOSE WAIT - ; Send a fin, then enter last-ack state - mov eax, TCB_LAST_ACK - mov [ebx + 28], eax - xor eax, eax - jmp sct_send - -sct_finwait1: - ; Send a fin, then enter finwait2 state - mov eax, TCB_FIN_WAIT_1 - mov [ebx + 28], eax - xor eax, eax - -sct_send: - mov eax, NET1OUT_QUEUE - - mov edx, [stack_ip] - mov ecx, [ sktAddr ] - mov ecx, [ ecx + 16 ] - cmp edx, ecx - jne sct_notlocal - mov eax, IPIN_QUEUE - -sct_notlocal: - ; Send it. - pop ebx - call queue - jmp sct_exit - -destroyTCB: - pop eax - ; Clear the socket varaibles - xor eax, eax - mov edi,ebx - mov ecx,SOCKETHEADERSIZE - cld - rep stosb - -sct_exit: - ret - - - -;*************************************************************************** -; Function -; socket_poll -; -; Description -; socket # in ebx -; returns count in eax. -; -;*************************************************************************** -socket_poll: - shl ebx, 12 - add ebx, sockets - mov eax, [ebx + 24] - - ret - - - -;*************************************************************************** -; Function -; socket_status -; -; Description -; socket # in ebx -; returns TCB state in eax. -; -;*************************************************************************** -socket_status: - shl ebx, 12 - add ebx, sockets - mov eax, [ebx + 28] - - ret - - - -;*************************************************************************** -; Function -; socket_read -; -; Description -; socket # in ebx -; returns # of bytes remaining in eax, data in bl -; -;*************************************************************************** -socket_read: - shl ebx, 12 - add ebx, sockets - mov eax, [ebx + 24] ; get count of bytes - mov ecx,1 - test eax, eax - jz sr2 - - dec eax - mov esi, ebx ; esi is address of socket - mov [ebx + 24], eax ; store new count - movzx ebx, byte [ebx + SOCKETHEADERSIZE] ; get the byte - add esi, SOCKETHEADERSIZE - mov edi, esi - inc esi - - mov ecx, (SOCKETBUFFSIZE - SOCKETHEADERSIZE) / 4 - cld - rep movsd - xor ecx, ecx - -sr1: - jmp sor_exit - -sr2: - xor bl, bl - -sor_exit: - ret - - - -;*************************************************************************** -; Function -; socket_write -; -; Description -; socket in ebx -; # of bytes to write in ecx -; pointer to data in edx -; returns 0 in eax ok, -1 == failed ( invalid socket, or -; could not queue IP packet ) -; -;*************************************************************************** -socket_write: - ; First, find the address of the socket descriptor - shl ebx, 12 - add ebx, sockets ; ebx = address of actual socket - - mov eax, 0xFFFFFFFF - ; If the socket is invalid, return with an error code - cmp [ebx], dword SOCK_EMPTY - je sw_exit - - - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je sw_exit - - ; Save the queue entry number - push eax - - ; save the pointers to the data buffer & size - push edx - push ecx - - ; convert buffer pointer eax to the absolute address - mov ecx, IPBUFFSIZE - mul ecx - add eax, IPbuffs - - mov edx, eax - - ; So, ebx holds the socket ptr, edx holds the IPbuffer ptr - - ; Fill in the IP header ( some data is in the socket descriptor) - mov eax, [ebx + 8] - mov [edx + 12], eax ; source IP - mov eax, [ebx + 16] - mov [edx + 16], eax ; Destination IP - - mov al, 0x45 - mov [edx], al ; Version, IHL - xor al, al - mov [edx + 1], al ; Type of service - - pop eax ; Get the UDP data length - push eax - - add eax, 20 + 8 ; add IP header and UDP header lengths - mov [edx + 2], ah - mov [edx + 3], al - xor al, al - mov [edx + 4], al - mov [edx + 5], al - mov al, 0x40 - mov [edx + 6], al - xor al, al - mov [edx + 7], al - mov al, 0x20 - mov [edx + 8], al - mov al, 17 - mov [edx + 9], al - - ; Checksum left unfilled - xor ax, ax - mov [edx + 10], ax - - ; Fill in the UDP header ( some data is in the socket descriptor) - mov ax, [ebx + 12] - mov [edx + 20], ax - - mov ax, [ebx + 20] - mov [edx + 20 + 2], ax - - pop eax - push eax - - add eax, 8 - mov [edx + 20 + 4], ah - mov [edx + 20 + 5], al - - ; Checksum left unfilled - xor ax, ax - mov [edx + 20 + 6], ax - - pop ecx ; count of bytes to send - mov ebx, ecx ; need the length later - pop eax ; get callers ptr to data to send - - ; Get the address of the callers data - mov edi,[0x3010] - add edi,TASKDATA.mem_start - add eax,[edi] - mov esi, eax - - mov edi, edx - add edi, 28 - cld - rep movsb ; copy the data across - - ; we have edx as IPbuffer ptr. - ; Fill in the UDP checksum - ; First, fill in pseudoheader - mov eax, [edx + 12] - mov [pseudoHeader], eax - mov eax, [edx + 16] - mov [pseudoHeader+4], eax - mov ax, 0x1100 ; 0 + protocol - mov [pseudoHeader+8], ax - add ebx, 8 - mov eax, ebx - mov [pseudoHeader+10], ah - mov [pseudoHeader+11], al - - mov eax, pseudoHeader - mov [checkAdd1], eax - mov [checkSize1], word 12 - mov eax, edx - add eax, 20 - mov [checkAdd2], eax - mov eax, ebx - mov [checkSize2], ax ; was eax!! mjh 8/7/02 - - call checksum - - ; store it in the UDP checksum ( in the correct order! ) - mov ax, [checkResult] - - ; If the UDP checksum computes to 0, we must make it 0xffff - ; (0 is reserved for 'not used') - cmp ax, 0 - jne sw_001 - mov ax, 0xffff - -sw_001: - mov [edx + 20 + 6], ah - mov [edx + 20 + 7], al - - ; Fill in the IP header checksum - mov eax, edx - mov [checkAdd1], eax - mov [checkSize1], word 20 - mov [checkAdd2], dword 0 - mov [checkSize2], word 0 - - call checksum - - mov ax, [checkResult] - mov [edx + 10], ah - mov [edx + 11], al - - ; Check destination IP address. - ; If it is the local host IP, route it back to IP_RX - - pop ebx - mov eax, NET1OUT_QUEUE - - mov ecx, [ edx + 16] - mov edx, [stack_ip] - cmp edx, ecx - jne sw_notlocal - mov eax, IPIN_QUEUE - -sw_notlocal: - ; Send it. - call queue - - xor eax, eax - -sw_exit: - ret - - - -;*************************************************************************** -; Function -; socket_write_tcp -; -; Description -; socket in ebx -; # of bytes to write in ecx -; pointer to data in edx -; returns 0 in eax ok, -1 == failed ( invalid socket, or -; could not queue IP packet ) -; -;*************************************************************************** -socket_write_tcp: - ; First, find the address of the socket descriptor - shl ebx, 12 - add ebx, sockets ; ebx = address of actual socket - - mov [sktAddr], ebx - - mov eax, 0xFFFFFFFF - ; If the socket is invalid, return with an error code - cmp [ebx], dword SOCK_EMPTY - je swt_exit - - ; If the sockets window timer is nonzero, do not queue packet - ; TODO - done - cmp [ebx + 72], dword 0 - jne swt_exit - - mov eax, EMPTY_QUEUE - call dequeue - cmp ax, NO_BUFFER - je swt_exit - - push eax - - mov bl, 0x10 ; ACK - - ; Get the address of the callers data - mov edi,[0x3010] - add edi,TASKDATA.mem_start - add edx,[edi] - mov esi, edx - - pop eax - push eax - - push ecx - call buildTCPPacket - pop ecx - - ; Check destination IP address. - ; If it is the local host IP, route it back to IP_RX - - pop ebx - push ecx - mov eax, NET1OUT_QUEUE - - mov edx, [stack_ip] - mov ecx, [ sktAddr ] - mov ecx, [ ecx + 16 ] - cmp edx, ecx - jne swt_notlocal - mov eax, IPIN_QUEUE - -swt_notlocal: - pop ecx - - push ebx ; save ipbuffer number - - call queue - - mov esi, [sktAddr] - - ; increament SND.NXT in socket - ; Amount to increment by is in ecx - add esi, 48 - call add_inet_esi - - pop ebx - - ; Copy the IP buffer to a resend queue - ; If there isn't one, dont worry about it for now - mov esi, resendQ - mov ecx, 0 - -swt003: - cmp ecx, NUMRESENDENTRIES - je swt001 ; None found - cmp [esi], byte 0xFF - je swt002 ; found one - inc ecx - add esi, 4 - jmp swt003 - -swt002: - push ebx - - ; OK, we have a buffer descriptor ptr in esi. - ; resend entry # in ecx - ; Populate it - ; socket # - ; retries count - ; retry time - ; fill IP buffer associated with this descriptor - - mov eax, [sktAddr] - sub eax, sockets - shr eax, 12 ; get skt # - mov [esi], al - mov [esi + 1], byte TCP_RETRIES - mov [esi + 2], word TCP_TIMEOUT - - inc ecx - ; Now get buffer location, and copy buffer across. argh! more copying,, - mov edi, resendBuffer - IPBUFFSIZE -swt002a: - add edi, IPBUFFSIZE - loop swt002a - - ; we have dest buffer location in edi - pop eax - ; convert source buffer pointer eax to the absolute address - mov ecx, IPBUFFSIZE - mul ecx - add eax, IPbuffs - mov esi, eax - - ; do copy - mov ecx, IPBUFFSIZE - cld - rep movsb - - inc dword [arp_rx_count] ; ************ TEST ONLY! - -swt001: - xor eax, eax - -swt_exit: - ret - - - -; Below, the main network layer source code is included -; - -include "queue.inc" -include "ip.inc" -include "tcp.inc" -include "udp.inc" -include "eth_drv/ethernet.inc" diff --git a/kernel/trunk/network/tcp.inc b/kernel/trunk/network/tcp.inc index 179f42535e..50060ddaad 100644 --- a/kernel/trunk/network/tcp.inc +++ b/kernel/trunk/network/tcp.inc @@ -14,6 +14,23 @@ ;; gets below 1KB ;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +; TCP TCB states +TCB_LISTEN equ 1 +TCB_SYN_SENT equ 2 +TCB_SYN_RECEIVED equ 3 +TCB_ESTABLISHED equ 4 +TCB_FIN_WAIT_1 equ 5 +TCB_FIN_WAIT_2 equ 6 +TCB_CLOSE_WAIT equ 7 +TCB_CLOSING equ 8 +TCB_LAST_ACK equ 9 +TCB_TIME_WAIT equ 10 +TCB_CLOSED equ 11 + +TWOMSL equ 10 ; # of secs to wait before closing socket + +TCP_RETRIES equ 5 ; Number of times to resend a packet +TCP_TIMEOUT equ 10 ; resend if not replied to in x hs ;******************************************************************* ; Interface @@ -27,6 +44,48 @@ ;******************************************************************* +; TCP Payload ( Data field in IP datagram ) +; +; 0 1 2 3 +; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +;20 | Source Port | Destination Port | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +;24 | Sequence Number | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +;28 | Acknowledgment Number | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +;32 | Data | |U|A|P|R|S|F| | +; | Offset| Reserved |R|C|S|S|Y|I| Window | +; | | |G|K|H|T|N|N| | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +;36 | Checksum | Urgent Pointer | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +;40 | Options | Padding | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; | data + + +struc TCP_PACKET +{ .SourcePort dw ? ;+00 + .DestinationPort dw ? ;+02 + .SequenceNumber dd ? ;+04 + .AckNumber dd ? ;+08 + .DataOffset db ? ;+12 - DataOffset[0-3 bits] and Reserved[4-7] + .Flags db ? ;+13 - Reserved[0-1 bits]|URG|ACK|PSH|RST|SYN|FIN + .Window dw ? ;+14 + .Checksum dw ? ;+16 + .UrgentPointer dw ? ;+18 + .Options rb 3 ;+20 + .Padding db ? ;+23 + .Data db ? ;+24 +} + +virtual at 0 + TCP_PACKET TCP_PACKET +end virtual + + ;*************************************************************************** ; Function @@ -116,7 +175,7 @@ tth001: cmp ecx, NUMRESENDENTRIES je tth003 ; None left cmp [esi], byte 0xFF - jne tth002 ; found one + jne tth002 ; found one inc ecx add esi, 4 jmp tth001 @@ -126,7 +185,7 @@ tth002: dec word [esi+2] mov ax, [esi+2] cmp ax, 0 - je tth002a + je tth002a inc ecx add esi, 4 jmp tth001 ; Timer not zero, so move on @@ -494,15 +553,9 @@ btp_001: mov [edx + 20 + 17], al ; Fill in the IP header checksum - mov eax, edx - mov [checkAdd1], eax - mov [checkSize1], word 20 - mov [checkAdd2], dword 0 - mov [checkSize2], word 0 + GET_IHL eax,edx ; get IP-Header length + stdcall checksum_jb,edx,eax ; buf_ptr, buf_size - call checksum - - mov ax, [checkResult] mov [edx + 10], ah mov [edx + 11], al diff --git a/kernel/trunk/network/udp.inc b/kernel/trunk/network/udp.inc index ff36d37ab2..06a75f95f4 100644 --- a/kernel/trunk/network/udp.inc +++ b/kernel/trunk/network/udp.inc @@ -19,18 +19,45 @@ ; udp_rx Handles received IP packets with the UDP protocol ; ;******************************************************************* - - - - + + +; +; UDP Payload ( Data field in IP datagram ) +; +; 0 1 2 3 +; 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +; +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; | Source Port | Destination Port | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; | Length ( UDP Header + Data ) | Checksum | +; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +; | UDP Data | +; +-+-+-.......... -+ +; + +struc UDP_PACKET +{ .SourcePort dw ? ;+00 + .DestinationPort dw ? ;+02 + .Length dw ? ;+04 - Length of (UDP Header + Data) + .Checksum dw ? ;+06 + .Data db ? ;+08 +} + +virtual at 0 + UDP_PACKET UDP_PACKET +end virtual + + ;*************************************************************************** ; Function -; udp_rx +; udp_rx [by Johnny_B] ; ; Description ; UDP protocol handler ; This is a kernel function, called by ip_rx ; IP buffer address given in edx +; IP buffer number in eax ; Free up (or re-use) IP buffer when finished ; ;*************************************************************************** @@ -134,4 +161,3 @@ udprx_001: pop eax call freeBuff ; Discard the packet ret - \ No newline at end of file