====== gPXE Network Driver Initialization ====== What happens when gPXE starts up?\\ How does a network driver get initialized?\\ Let's follow the call stack at key points from instantiation.\\ ===== Reaching probe ===== * src/core/main.c >> ''main()'' -- Entry point. * src/core/init.c >> ''startup()'' * src/core/device.c >> ''probe_devices()'' -- Probe buses sequentially. * src/core/device.c >> ''rootdev_probe()'' -- Probe this bus. * ''%%{struct root_device}->driver->probe()%%'' == src/drivers/bus/pci.c >> ''pcibus_probe()'' -- Probe PCI devices sequentially. * src/drivers/bus/pci.c >> ''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(). ===== Reaching close ===== * src/core/main.c >> ''main()'' * src/usr/autoboot.c >> ''autoboot()'' -- Boot network devices sequentially. * src/usr/autoboot.c >> ''close_all_netdevs()'' * src/usr/ifmgmt.c >> ''ifclose()'' * src/net/netdevice.c >> ''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(). ===== Reaching open ===== * src/usr/autoboot.c >> ''autoboot()'' -- Still booting network devices sequentially. * src/usr/autoboot.c >> ''netboot()'' -- Boot this network device * src/usr/ifmgmt.c >> ''ifopen()'' * src/net/netdevice.c >> ''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. ===== root_device and pci_device structs ===== 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.