Next Previous Contents

9. Writing an Etherboot Driver

So Etherboot does not have a driver for your network adapter and you want to write one. You should have a good grasp of C, especially with respect to bit operations. You should also understand hardware interfacing concepts, such as the fact that the x86 architecture has a separate I/O space and that peripherals are commanded with out instructions and their status read with in instructions. A microprocessor course such as those taught in engineering or computer science curricula would have given you the fundamentals. (Note to educators and students in computer engineering: An Etherboot driver should be feasible as a term project for a final year undergraduate student. I estimate about 40 hours of work is required. I am willing to be a source of technical advice.)

Next you need a development machine. This can be your normal Linux machine. You need another test machine, networked to the development machine. This should be a machine you will not feel upset rebooting very often. So the reset button should be in working condition. :-) It should have a floppy drive on it but does not need a hard disk, and in fact a hard disk will slow down rebooting. Needless to say, you need a unit of the adapter you are trying to write a driver for. You should gather all the documentation you can find for the hardware, from the manufacturer and other sources.

There are several types of network adapter architecture. The simplest to understand is probably programmed I/O. This where the controller reads incoming packets into memory that resides on the adapter and the driver uses in instructions to extract the packet data, word by word, or sometimes byte by byte. Similarly, packets are readied for transmission by writing the data into the adapter's memory using out instructions. This architecture is used for example on the NE2000 and 3C509. The disadvantage of this architecture is the load on the CPU imposed by the I/O. However this is of no import to Etherboot (who cares how loaded the CPU is during booting), but will be to Linux. Next in the sophistication scale are shared memory adapters such as the Western Digital or SMC series, of which the WD8013 is a good example. Here the adapter's memory is also accessible in the memory space of the main CPU. Transferring data between the driver and the adapter is done with memory copy instructions. Load on the CPU is light. Adapters in this category are some of the best performers for the ISA bus. Finally there are bus mastering cards such as the Lance series for the ISA bus and practically all good PCI adapters (but not the NE2000 PCI). Here the data is transferred between the main memory and the adapter controller using Direct Memory Access.

Examine the file skel.c, in the src directory, which is a template for a driver. You may also want to examine a working driver. You will see that an Etherboot driver requires 5 functions to be provided:

Only the probe routine needs to be public, all the other routines should be static and private to the driver module. Similarly all data in the routine should be static and private.

A prototype for the probe routine should be added to the file config.c, conditional on INCLUDE_NAMEOFNIC. NAMEOFNIC is derived from the name of the driver source file for your adapter by uppercasing alphabets and converting hyphen to underscore. If the file is pop-sicle.c, then the symbol is INCLUDE_POP_SICLE. Also conditional on INCLUDE_NAMEOFNIC should be a struct entry containing the name of the driver and a pointer to the probe routine. The third element of the structure should be pci_probeaddrs in the case of PCI adapters, otherwise 0.

If the NIC is a PCI adapter, then you also need to put an entry in the pci_nic_list array with the name, vendor and id fields filled in. You can obtain the vendor and device ids from the file /usr/include/linux/pci.h. It is also displayed by PCI BIOSes on bootup, or you can use the lspci program from the pciutils package to discover the ids. The other fields will be filled in by the pci routines. The symbol INCLUDE_NAMEOFNIC should be used to set INCLUDE_PCI.

Then add an entry to the file NIC so that the build process will create Makefile rules for it in the file Roms. The build process will cause the driver object will be pulled in from the driver library. Use the rule for driver.fd0 or the command cat floppyboot.bin driver.rom > /dev/fd0 to write another instance of the driver to the floppy for testing. Use lots of printf statements to track where execution has reached and to display the status of various variables and registers in the code. You should expect to do this dance with the development machine, floppy disk and target machine many many times.

Now set up the various required services, i.e. BOOTP/DHCP, tftp, etc. on the development machine. You should go through the setup process with a supported adapter card on a test machine so that you know that the network services are working and what to expect to see on the test machine.

When coding, first get the probe routine working. You will need to refer to the programmer's guide to the adapter when you do this. You can also get some information by reading a Linux or FreeBSD driver. You may need to get the reset routine working at this time.

Next, get the transmit routine working. To check that packets are going out on the wire, you can use tcpdump on the development machine to snoop on the Ethernet. The first packet to be sent out by Etherboot will be a broadcast query packet, on UDP port 67. Note that you do not need interrupts at all. You should ensure the packet is fully transmitted before returning from this routine. You may also wish to implement a timeout to make sure the driver doesn't get stuck inside transmit if it fails to complete.

Next, get the receive routine working. If you already have the transmit routine working correctly you should be getting a reply from the BOOTP/DHCP server. Again, you do not need interrupts, unlike drivers from Linux and other operating systems. This means you just have to read the right register on the adapter to see if a packet has arrived. Note that you should NOT loop in the receive routine until a packet is received. Etherboot needs to do other things so if you loop in the poll routine, it will not get a chance to do those tasks. Just return 0 if there is no packet awaiting and the main line will call the poll routine again later.

Finally, get the disable routine working. This may simply be a matter of turning off something in the adapter.

Things that may complicate your coding are constraints imposed by the hardware. Some adapters require buffers to be on word or doubleword boundaries. See rtl8139.c for an example of this. Some adapters need a wait after certain operations.

When you get something more or less working, release early. People on the mailing lists can help you find problems or improve the code. Besides you don't want to get run over by a bus and then the world never gets to see your masterpiece, do you? :-)

Your opus should be released under GPL, BSD or a similar Open Source license, otherwise people will have problems using your code, as most of the rest of Etherboot is GPLed.


Next Previous Contents