What happens when gPXE starts up?
How does a network driver get initialized?
Let's follow the call stack at key points from instantiation.
main()
– Entry point.startup()
probe_devices()
– Probe buses sequentially.rootdev_probe()
– Probe this bus.{struct root_device}->driver->probe()
== src/drivers/bus/pci.c » pcibus_probe()
– Probe PCI devices sequentially.pci_probe()
– Probe this device.{struct pci_driver}->probe()
== src/drivers/net/NAME.c » NAME_probe()
– The network driver's probe()
routine is finally reached.
At this point netdev_init()
associates netdev with driver functions.
register_netdev()
adds to the device list.
We return up the call stack to main().
main()
autoboot()
– Boot network devices sequentially.close_all_netdevs()
ifclose()
netdev_close()
{struct net_device}->op->close()
== src/drivers/net/NAME.c » NAME_close()
– The network driver's close()
routine is reached.
All network devices are closed before attempting to boot each network device.
We return up the call stack to autoboot().
autoboot()
– Still booting network devices sequentially.netboot()
– Boot this network deviceifopen()
netdev_open()
{struct net_device}->op->open()
== src/drivers/net/NAME.c » NAME_open()
– The network driver's open()
routine is reached.At this point transmit and receive are enabled.
Both struct root_device
and struct pci_device
have a special function in gPXE. Bus drivers are root_device
s, thus there is one for PCI, ISA, etc. PCI devices are self-explanatory. Both root_device
and pci_device
structs are defined within their respective driver code. These structs hold function pointers to essential interface routines, such as probe()
and remove()
. The __pci_driver
and __root_driver
tags cause the drivers to be added to a list of modules, resulting in their probe()
routines being called during initialization.