My NE2000 send doesn't work

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
mariuszp
Member
Member
Posts: 593
Joined: Sat Oct 16, 2010 3:38 pm

My NE2000 send doesn't work

Post by mariuszp »

I have attempted to write a driver for the NE2000 NIC:

Code: Select all

static void ne2k_setremaddr(NeInterface *nif, uint32_t val)
{
	outb(nif->iobase + 0x08, (uint8_t) (val & 0xFF));
	outb(nif->iobase + 0x09, (uint8_t) ((val >> 8) & 0xFF));
};

static void ne2k_setremcount(NeInterface *nif, size_t val)
{
	outb(nif->iobase + 0x0A, (uint8_t) (val & 0xFF));
	outb(nif->iobase + 0x0B, (uint8_t) ((val >> 8) & 0xFF));
};

static void ne2k_write(NeInterface *nif, uint32_t addr, const void *buffer, size_t size)
{
	ne2k_setremaddr(nif, addr);
	ne2k_setremcount(nif, size);

	outb(nif->iobase + 0x0E, 0x48);		// set byte-wide access
	const uint8_t *scan = (const uint8_t*) buffer;

	outb(nif->iobase, 0x12);		// write DMA + start
	while (size--)
	{
		outb(nif->iobase + 0x10, *scan++);
	};
	
	while ((inb(nif->iobase + 0x07) & 0x40) == 0);
};

static void ne2k_settxcount(NeInterface *nif, size_t count)
{
	outb(nif->iobase + 0x05, (uint8_t) (count & 0xFF));
	outb(nif->iobase + 0x06, (uint8_t) ((count >> 8) & 0xFF));
};

static void ne2k_send(NetIf *netif, const void *frame, size_t framelen)
{
	(void)netif;
	(void)frame;
	(void)framelen;

	kprintf_debug("ne2k_send called (size=%d):\n", (int) framelen);
	EthernetHeader *head = (EthernetHeader*) frame;
	kprintf_debug("\tDST: %x:%x:%x:%x:%x:%x\n", head->dest.addr[0], head->dest.addr[1], head->dest.addr[2],
						head->dest.addr[3], head->dest.addr[4], head->dest.addr[5]);
	kprintf_debug("\tSRC: %x:%x:%x:%x:%x:%x\n", head->src.addr[0], head->src.addr[1], head->src.addr[2],
						head->src.addr[3], head->src.addr[4], head->src.addr[5]);
	kprintf_debug("\tTYP: 0x%x\n", __builtin_bswap16(head->type));
	kprintf_debug("\tCHK: 0x%x\n", ether_checksum(frame, framelen));

	NeInterface *nif = (NeInterface*) netif->drvdata;
	spinlockAcquire(&nif->lock);
	
	// write the frame to the transmit buffer
	ne2k_write(nif, (16*1024)/256, frame, framelen);
	
	// specify the location of transmission buffer in NIC memory
	outb(nif->iobase + 0x04, (16*1024)/256);
	
	// specify the size of the frame
	ne2k_settxcount(nif, framelen);

	// transmit
	outb(nif->iobase, 0x26);
	
	// wait for transmit to complete
	while ((inb(nif->iobase) & 0x04) == 0);
	
	spinlockRelease(&nif->lock);
	kprintf_debug("PACKET SENT\n");
};
When I attempt to send an ICMP Echo Request to 255.255.255.255 (which the OS automatically maps to MAC ff:ff:ff:ff:ff:ff) just as a test, I get the following in the debug console (from the kprintf_debug()s):

Code: Select all

PING 255.255.255.255 (255.255.255.255)
ne2k_send called (size=64):
	DST: ff:ff:ff:ff:ff:ff
	SRC: b0:c4:20:0:0:0
	TYP: 0x800
	CHK: 0x2144df1c
PACKET SENT
But in the ne2k-pktlog file from Bochs I get:

Code: Select all

vnet packetmover readable log file
TFTP root = xl0
host MAC address = b0:c4:20:00:00:03
guest MAC address = b0:c4:20:00:00:00
--
a packet from guest to host, length 64
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  ................
--
What this code is trying to do is write the frame to NIC memory (using the "DMA Write") and then I transmit from that buffer, but clearly it's sending all zeroes for some reason.

Does anyone know why this is happening?
mariuszp
Member
Member
Posts: 593
Joined: Sat Oct 16, 2010 3:38 pm

Re: My NE2000 send doesn't work

Post by mariuszp »

Bump
User avatar
SpyderTL
Member
Member
Posts: 1074
Joined: Sun Sep 19, 2010 10:05 pm

Re: My NE2000 send doesn't work

Post by SpyderTL »

This code is a little hard for me to follow, but everything appears to be right at first glance. So the problem is probably with one of your assumptions.

Add the buffer address and the first 64 bytes to your debug output.

Also, try a different OS using this exact setup and make sure the network works properly. Let us know what you find out.
Project: OZone
Source: GitHub
Current Task: LIB/OBJ file support
"The more they overthink the plumbing, the easier it is to stop up the drain." - Montgomery Scott
mariuszp
Member
Member
Posts: 593
Joined: Sat Oct 16, 2010 3:38 pm

Re: My NE2000 send doesn't work

Post by mariuszp »

I have added what you have requested to the debug output:

Code: Select all

PING 255.255.255.255 (255.255.255.255)
ne2k_send called (size=64):
	DST: ff:ff:ff:ff:ff:ff
	SRC: b0:c4:20:0:0:0
	TYP: 0x800
	CRC: 0x2144df1c
	Buffer address: 0xFFFF8100017CB2D0
ff ff ff ff ff ff b0 c4 20 00 00 00 08 00 45 00 
00 1c 01 00 00 00 40 01 79 e2 00 00 00 00 ff ff 
ff ff 08 00 ef ff 08 00 00 00 00 00 00 00 00 00 
00 00 00 00 00 00 00 00 00 00 00 00 84 da c8 85 
PACKET SENT
"Buffer address" is the address of 'frame'. The address it shows is on the kernel heap. Again it sends only zeroes.

My bochsrc file is as follows:

Code: Select all

ata0-master: type=disk, mode=flat, path=hdd.bin, cylinders=306, heads=4, spt=17
ata0-slave: type=cdrom, path=out/glidix.iso, status=inserted
megs: 512
magic_break: enabled=1
boot: cdrom
port_e9_hack: enabled=1
pci: enabled=1, chipset=i440fx, slot1=pcivga, slot2=ne2k
cpuid: apic=xapic
ne2k: ioaddr=0x300, irq=10, mac=b0:c4:20:00:00:00, ethmod=vnet
(Using "vnet" for easy debugging).
mariuszp
Member
Member
Posts: 593
Joined: Sat Oct 16, 2010 3:38 pm

Re: My NE2000 send doesn't work

Post by mariuszp »

OK guys i figured it out.

Code: Select all

ne2k_write(nif, (16*1024)/256, frame, framelen);
Should actually be:

Code: Select all

ne2k_write(nif, 16*1024, frame, framelen);
Because ne2k_write() accepts the actual ring buffer address, not the page number.
Ready4Dis
Member
Member
Posts: 571
Joined: Sat Nov 18, 2006 9:11 am

Re: My NE2000 send doesn't work

Post by Ready4Dis »

Because ne2k_write() accepts the actual ring buffer address, not the page number.
Thanks for the heads up, always nice when someone comes back and posts the solution when they find it!
Post Reply