Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to list network devices in NASM (custom OS)

I have a custom, DOS-like OS built in NASM completely (no C code). It is very modest (it does have a FAT file system, few apps, is in real mode, etc.) I want to write a command that will list all the network devices (network cards) that are currently connected.

My assumptions go like this: I will need to write a driver for the network card (I'd put it manually inside kernel for simplicity, so dynamic loading would NOT exist), but it would be enough for that driver to just provide the name of the card, the network card wouldn't actually need to work. How do I tell the OS to connect that function to precisely that one network card? This is what I'm in the blue about, I have no idea how the OS usually matches a piece of hardware to code (its driver(s)).

like image 697
Sasha Avatar asked Nov 20 '25 21:11

Sasha


1 Answers

Since it appears from your comments that you have Dosbox supporting an NE2000 card then the code below should detect the presence of an NE2000 card (A port base of 0x300 is assumed). The code is a DOS COM program I wrote and should be compilable with a command like nasm ne2kchk.asm -fbin -o ne2kchk.com

NS_DATAPORT    EQU    0x10    ; NatSemi-defined port window offset.
NE_DATAPORT    EQU    0x10    ; NatSemi-defined port window offset.
NS_RESET       EQU    0x1f    ; Issue a read to reset, a write to clear.

NE1SM_START_PG EQU    0x20    ; First page of TX buffer
NE1SM_STOP_PG  EQU    0x40    ; Last page +1 of RX ring
NESM_START_PG  EQU    0x40    ; First page of TX buffer
NESM_STOP_PG   EQU    0x80    ; Last page +1 of RX ring

E8390_CMD      EQU    0x00    ; The command register (for all pages)
E8390_STOP     EQU    0x01    ; Stop and reset the chip
E8390_START    EQU    0x02    ; Start the chip, clear reset
E8390_RREAD    EQU    0x08    ; Remote read
E8390_NODMA    EQU    0x20    ; Remote DMA
E8390_PAGE0    EQU    0x00    ; Select page chip registers
E8390_PAGE1    EQU    0x40    ; using the two high-order bits
E8390_PAGE2    EQU    0x80
E8390_PAGE3    EQU    0xC0    ; Page 3 is invalid on the real 8390.

E8390_RXOFF    EQU    0x20    ; EN0_RXCR: Accept no packets
E8390_TXOFF    EQU    0x02    ; EN0_TXCR: Transmitter off

               ; Page 0 register offsets.
EN0_CLDALO     EQU    0x01    ; Low byte of current local dma addr  RD
EN0_STARTPG    EQU    0x01    ; Starting page of ring bfr WR
EN0_CLDAHI     EQU    0x02    ; High byte of current local dma addr     RD
EN0_STOPPG     EQU    0x02    ; Ending page +1 of ring bfr WR
EN0_BOUNDARY   EQU    0x03    ; Boundary page of ring bfr RD WR
EN0_TSR        EQU    0x04    ; Transmit status reg RD
EN0_TPSR       EQU    0x04    ; Transmit starting page WR
EN0_NCR        EQU    0x05    ; Number of collision reg RD
EN0_TCNTLO     EQU    0x05    ; Low     byte of tx byte count WR
EN0_FIFO       EQU    0x06    ; FIFO RD
EN0_TCNTHI     EQU    0x06    ; High byte of tx byte count WR
EN0_ISR        EQU    0x07    ; Interrupt status reg RD WR
EN0_CRDALO     EQU    0x08    ; low byte of current remote dma address RD
EN0_RSARLO     EQU    0x08    ; Remote start address reg 0
EN0_CRDAHI     EQU    0x09    ; high byte, current remote dma address RD
EN0_RSARHI     EQU    0x09    ; Remote start address reg 1
EN0_RCNTLO     EQU    0x0a    ; Remote byte count reg WR
EN0_RCNTHI     EQU    0x0b    ; Remote byte count reg WR
EN0_RSR        EQU    0x0c    ; rx status reg RD
EN0_RXCR       EQU    0x0c    ; RX configuration reg WR
EN0_TXCR       EQU    0x0d    ; TX configuration reg WR
EN0_COUNTER0   EQU    0x0d    ; Rcv alignment error counter RD
EN0_DCFG       EQU    0x0e    ; Data configuration reg WR
EN0_COUNTER1   EQU    0x0e    ; Rcv CRC error counter RD
EN0_IMR        EQU    0x0f    ; Interrupt mask reg WR
EN0_COUNTER2   EQU    0x0f    ; Rcv missed frame error counter RD

PORT_BASE      EQU    0x300   ; Default base port

[BITS 16]

    org 0x100

section .text

start:
    push   cs
    pop    ds

    ; Probe for NE2000 card

    ; Try non destructive test first
    mov    dx, PORT_BASE+E8390_CMD
    in     al, dx
    cmp    al, 0xff
    jz     .s_notfound

    ; Attempt potentially destuctive tests
    mov    al, E8390_NODMA | E8390_PAGE1 | E8390_STOP
    mov    dx, PORT_BASE+E8390_CMD
    out    dx, al    ; Receive alignment error counter
    mov    dx, PORT_BASE+EN0_COUNTER0
    in     al, dx
    mov    cl, al    ; Save to REGD (CL)
    mov    al, 0xff
    out    dx, al
    mov    al, E8390_NODMA | E8390_PAGE0
    mov    dx, PORT_BASE+E8390_CMD
    out    dx, al
    mov    dx, PORT_BASE+EN0_COUNTER0
    in     al, dx    ; Clear the counter by reading.
    test   al, al
    jz     .s_found  ; If al is clear then card was found

    ; Card not found
.s_notfound:
    xchg   al, cl    ; Temporarily save al to avoid clobber
    out    dx, al
    mov    ah, 0x09
    mov    dx, notfound_str
    int    0x21
    xchg   al, cl    ; Restore al. al = error value to return
    jmp    .s_exit

    ; Card found
.s_found:
    mov    ah, 0x09
    mov    dx, found_str
    int    0x21
    xor    al, al    ; Clear the error code

    ; exit with al = errcode
.s_exit:
    mov    ah, 0x4C
    int    0x21

notfound_str db "NE2000 not found", 0x0a, 0x0d, "$"
found_str    db "NE2000 found", 0x0a, 0x0d, "$"

The code above is an adaptation of "C" code that I found in the Debian nictool code available here . It can be found in the file ne2k-diags.c. It seems more information (datasheets) are available for the rtl8019 which is a clone of the NE2000. The 8390NIC that is at the heart of these devices is documented here. The 8390 documentation discusses how to send and receive data. An excerpt of the "C" code that I based mine on was:

printf("Checking the ethercard at %#3x.\n", port_base);
{   int regd;
    long ioaddr = port_base;

    outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD);
    regd = inb_p(ioaddr + 0x0d);
    printk("  Receive alignment error counter (%#lx) is %2.2x\n",
           ioaddr + 0x0d, regd);
    outb_p(0xff, ioaddr + 0x0d);
    outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD);
    inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */
    if (inb_p(ioaddr + EN0_COUNTER0) != 0) {
        outb(regd, ioaddr + 0x0d);  /* Restore the old values. */
        printk("  Failed initial NE2000 probe, value %2.2x.\n",
               inb(ioaddr + EN0_COUNTER0));
    } else
        printk("  Passed initial NE2000 probe, value %2.2x.\n",
               inb(ioaddr + EN0_COUNTER0));

}

The code above is the initial probe but there is more "C" code in the same file that tries to detect some of the specific variants and query the card signature.

like image 60
Michael Petch Avatar answered Nov 23 '25 14:11

Michael Petch



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!