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_devices, 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.