forked from KolibriOS/kolibrios
1682 lines
48 KiB
PHP
1682 lines
48 KiB
PHP
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
;; ;;
|
||
|
;; ETHERNET.INC ;;
|
||
|
;; ;;
|
||
|
;; Ethernet network layer for Menuet OS ;;
|
||
|
;; ;;
|
||
|
;; Version 0.4 22 September 2003 ;;
|
||
|
;; ;;
|
||
|
;; This file contains the following: ;;
|
||
|
;; PCI bus scanning for valid devices ;;
|
||
|
;; Table of supported ethernet drivers ;;
|
||
|
;; Code to identify and activate a supported driver ;;
|
||
|
;; ARP handler ;;
|
||
|
;; Driver interface to the IP layer ;;
|
||
|
;; Gateway support ;;
|
||
|
;; ;;
|
||
|
;; Individual driver files are included here ;;
|
||
|
;; ;;
|
||
|
;; The PCI bus scanning code was ported from the etherboot ;;
|
||
|
;; 5.0.6 project. The copyright statement for that code is ;;
|
||
|
;; ;;
|
||
|
;; GNU GENERAL PUBLIC LICENSE ;;
|
||
|
;; Version 2, June 1991 ;;
|
||
|
;; ;;
|
||
|
;; remaining parts Copyright 2002 Mike Hibbett ;;
|
||
|
;; mikeh@oceanfree.net ;;
|
||
|
;; ;;
|
||
|
;; See file COPYING for details ;;
|
||
|
;; ;;
|
||
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||
|
|
||
|
;********************************************************************
|
||
|
; Interface
|
||
|
; ethernet_driver called by stack_handler in stack.inc
|
||
|
; eth_probe called by app_stack_handler in stack.inc
|
||
|
;
|
||
|
;********************************************************************
|
||
|
|
||
|
; Some useful information on data structures
|
||
|
|
||
|
; Ethernet Packet - ARP Request example
|
||
|
;
|
||
|
; 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
|
||
|
;
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
; | Dest H/W Address |
|
||
|
; | ( 14 byte header ) |
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
; | | Source H/W Address |
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
; | |
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
; | Protocol - ARP 08 06 |
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
; | H/W Type 00 01 | Protocol Type 08 00 |
|
||
|
; | ( ARP Request packet ) |
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
; | HLen 0x06 | PLen 0x04 | OpCode 00 01 |
|
||
|
; | ( 0001 for request, 0002 for reply ) |
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
; | Source Hardware Address ( MAC Address ) |
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
; | | Source IP Address |
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
; | | Destination Hardware Address |
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
; | |
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
; | Destination IP Address |
|
||
|
; +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||
|
|
||
|
; 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
|
||
|
|
||
|
; PCICards
|
||
|
; ========
|
||
|
; PCI vendor and hardware types for hardware supported by the above drivers
|
||
|
; If you add a driver, ensure you update this datastructure, otherwise the
|
||
|
; card will not be probed.
|
||
|
; Each driver is defined by 4 double words. These are
|
||
|
; PCIVendorDevice probeFunction ResetFunction PollFunction transmitFunction
|
||
|
; The last entry must be kept at all zeros, to indicate the end of the list
|
||
|
; As a PCI driver may support more than one hardware implementation, there may
|
||
|
; be several lines which refer to the same functions.
|
||
|
; The first driver found on the PCI bus will be the one used.
|
||
|
|
||
|
PCICARDS_ENTRY_SIZE equ 20 ; Size of each PCICARDS entry
|
||
|
|
||
|
iglobal
|
||
|
PCICards:
|
||
|
dd 0x12098086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit
|
||
|
dd 0x10298086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit
|
||
|
dd 0x12298086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit
|
||
|
dd 0x10308086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit
|
||
|
dd 0x24498086, I8255x_probe, I8255x_reset, I8255x_poll, I8255x_transmit
|
||
|
dd 0x802910ec, rtl8029_probe, rtl8029_reset, rtl8029_poll, rtl8029_transmit
|
||
|
dd 0x12111113, rtl8029_probe, rtl8029_reset, rtl8029_poll, rtl8029_transmit
|
||
|
dd 0x813910ec, rtl8139_probe, rtl8139_reset, rtl8139_poll, rtl8139_transmit
|
||
|
dd 0x590010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x592010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x597010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x595010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x595110b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x595210b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x900010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x900110b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x900410b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x900510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x900610b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x900A10b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x905010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x905110b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x905510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x905810b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x905A10b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x920010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x980010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x980510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x764610b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x505510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x605510b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x605610b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x5b5710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x505710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x515710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x525710b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x656010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x656210b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x656410b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x450010b7, e3c59x_probe, e3c59x_reset, e3c59x_poll, e3c59x_transmit
|
||
|
dd 0x09001039, SIS900_probe, SIS900_reset, SIS900_poll, SIS900_transmit
|
||
|
dd 0x20001022, pcnet32_probe, pcnet32_reset, pcnet32_poll, pcnet32_xmit
|
||
|
dd 0x26251022, pcnet32_probe, pcnet32_reset, pcnet32_poll, pcnet32_xmit
|
||
|
dd 0x20011022, pcnet32_probe, pcnet32_reset, pcnet32_poll, pcnet32_xmit
|
||
|
; following card is untested
|
||
|
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
|
||
|
node_addr: db 0,0,0,0,0,0
|
||
|
eth_rx_data_len: dw 0
|
||
|
eth_status: dd 0
|
||
|
io_addr: dd 0
|
||
|
hdrtype: db 0
|
||
|
vendor_device: dd 0
|
||
|
pci_data: dd 0
|
||
|
pci_dev: dd 0
|
||
|
pci_bus: dd 0
|
||
|
|
||
|
; These will hold pointers to the selected driver functions
|
||
|
drvr_probe: dd 0
|
||
|
drvr_reset: dd 0
|
||
|
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
|
||
|
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
|
||
|
|
||
|
; 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
|
||
|
|
||
|
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
|
||
|
|
||
|
uglobal
|
||
|
ARPTable:
|
||
|
times ( ARP_TABLE_SIZE - ARP_TABLE_ENTRIES ) * ARP_ENTRY_SIZE db 0
|
||
|
endg
|
||
|
|
||
|
iglobal
|
||
|
NumARP: db ARP_TABLE_ENTRIES
|
||
|
endg
|
||
|
|
||
|
;***************************************************************************
|
||
|
; Function
|
||
|
; eth_probe
|
||
|
; Description
|
||
|
; Searches for an ethernet card. If found, the card is enabled and
|
||
|
; the ethernet -> IP link established
|
||
|
;
|
||
|
; This function scans the PCI bus looking for a supported device.
|
||
|
; ISA bus is currently not supported.
|
||
|
;
|
||
|
; eax is 0 if no hardware found
|
||
|
;***************************************************************************
|
||
|
eth_probe:
|
||
|
; Find a card on the PCI bus, and get it's address
|
||
|
call scan_bus ; Find the ethernet cards PIC address
|
||
|
xor eax, eax
|
||
|
cmp [io_addr], eax
|
||
|
je ep_00x ; Return 0 in eax if no cards found
|
||
|
|
||
|
call dword [drvr_probe] ; Call the drivers probe function
|
||
|
|
||
|
mov eax, [io_addr] ; return a non zero value
|
||
|
|
||
|
ep_00x:
|
||
|
ret
|
||
|
|
||
|
;***************************************************************************
|
||
|
; Function
|
||
|
; ethernet_driver
|
||
|
;
|
||
|
; Description
|
||
|
; The ethernet RX and TX handler
|
||
|
; This is a kernel function, called by stack_handler
|
||
|
;
|
||
|
;***************************************************************************
|
||
|
ethernet_driver:
|
||
|
; Do nothing if the driver is inactive
|
||
|
cmp [ethernet_active], byte 0
|
||
|
je eth_exit
|
||
|
|
||
|
call eth_rx
|
||
|
call eth_tx
|
||
|
|
||
|
eth_exit:
|
||
|
ret
|
||
|
|
||
|
;***************************************************************************
|
||
|
; Function
|
||
|
; eth_rx
|
||
|
;
|
||
|
; Description
|
||
|
; Polls the ethernet card for received data. Extracts if present
|
||
|
; Depending on the Protocol within the packet:
|
||
|
; ARP : Pass to ARP_handler. This may result in an ARP reply
|
||
|
; being tx'ed
|
||
|
; IP : Store in an IP buffer
|
||
|
;
|
||
|
;***************************************************************************
|
||
|
eth_rx:
|
||
|
xor ax, ax
|
||
|
mov [eth_rx_data_len], ax
|
||
|
call dword [drvr_poll] ; Call the drivers poll function
|
||
|
|
||
|
mov ax, [eth_rx_data_len]
|
||
|
cmp ax, 0
|
||
|
je erx_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
|
||
|
|
||
|
cmp ax, ETHER_IP
|
||
|
je erx_002 ; It's IP
|
||
|
|
||
|
; inc dword [dumped_rx_count]
|
||
|
|
||
|
jmp erx_exit ; If not IP or ARP, ignore
|
||
|
|
||
|
erx_001:
|
||
|
mov eax, [arp_rx_count]
|
||
|
inc eax
|
||
|
mov [arp_rx_count], eax
|
||
|
|
||
|
; 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
|
||
|
|