Skip to content

Network Boot (PXE)

PXE (Preboot eXecution Environment) is a network-based alternative to loading a bootloader from disk. PCI already mentions a network card’s expansion ROM as the place PXE boot code lives; this article covers how that code actually gets a bootloader running over the network before any disk is ever touched.

During its own boot device enumeration, firmware discovers a network card exposing a PXE-capable expansion ROM the same way it discovers any bootable device, and, if PXE boot is selected (by boot order, user choice, or a lack of any other bootable device), firmware loads and executes that ROM’s own code directly, before touching a disk controller at all. This is what makes PXE fundamentally different from every other boot path this wiki covers: the code that actually implements the network protocols below runs from the NIC’s own firmware image, not from anything the kernel or an OS installer provides, and firmware’s role is limited to locating and running that ROM code, not implementing PXE itself.

The PXE ROM’s first job is standard DHCP, requesting an IP address the same way any DHCP client on a normal network would, but with PXE-specific options included in the request: the client identifies itself as PXE-capable, and a properly configured DHCP server (or a companion PXE proxy DHCP server running alongside an otherwise unmodified ordinary DHCP server) responds with the usual IP configuration plus two additional pieces of information, the address of a TFTP server and the filename of the bootloader to request from it.

DHCPDISCOVER (client, PXE options set)
-> DHCPOFFER (server): IP address, subnet, gateway,
next-server = 10.0.0.5,
filename = "pxelinux.0"

Some networks split this across two distinct DHCP exchanges rather than one, an ordinary DHCP server providing address configuration and a separate proxyDHCP server providing only the PXE-specific fields, specifically so an existing DHCP infrastructure with no PXE awareness at all can be paired with PXE boot support added on the side, without reconfiguring the primary DHCP service itself.

With the boot server’s address and the bootloader’s filename in hand, the PXE ROM requests that file over TFTP (Trivial File Transfer Protocol), a deliberately minimal protocol built on UDP, exchanging the bootloader in small, individually acknowledged blocks (512 bytes each in the original specification) rather than anything resembling a full-featured file transfer protocol.

RRQ "pxelinux.0" octet (client -> server, port 69)
DATA block 1 (512 bytes) (server -> client)
ACK block 1 (client -> server)
DATA block 2 (512 bytes)
ACK block 2
...
DATA block N (< 512 bytes) -- signals end of transfer
ACK block N

TFTP’s simplicity is deliberate rather than a limitation worth working around: it needs to be implementable entirely within a NIC’s own constrained expansion ROM, with no filesystem, no connection state beyond the current block number, and no authentication, trading every feature a general-purpose transfer protocol might offer for a implementation small and simple enough to fit where PXE actually has to run.

After the transfer, boot proceeds normally

Section titled “After the transfer, boot proceeds normally”

Once TFTP has copied the bootloader into memory, the PXE ROM transfers control to it exactly the way the boot process already describes control passing to a disk-loaded bootloader: same CPU state, same expectations about what that code does next. From this point forward, nothing about the rest of boot is PXE-specific at all; the downloaded bootloader can itself use TFTP to fetch a kernel image and further files (a common pattern for network-booting a full Linux installer, for instance) or simply proceed exactly as it would have if it had been loaded from a local disk in the first place.

A PXE-capable environment for kernel development is straightforward to set up under QEMU without any real network hardware at all: -netdev combined with a TFTP root directory and boot filename option lets QEMU’s own virtual network stack serve DHCP and TFTP directly, letting a developer test a network boot path without configuring separate physical DHCP and TFTP servers. Because PXE ROM code space is limited, and because it has no filesystem or partition-table awareness whatsoever, the file it fetches is almost always a small, dedicated bootloader stage (pxelinux.0, or an equivalent) rather than a full kernel directly, mirroring the same staged-loading pattern Bootloaders already covers for disk-based boot.

  1. ^ Intel and Systemsoft, Preboot Execution Environment (PXE) Specification: the formal specification defining the DHCP extensions and TFTP-based boot flow described above.
  • PCI: the expansion ROM a NIC’s PXE boot code actually lives in.
  • The Boot Process: once the downloaded bootloader takes control, the rest of boot proceeds exactly as a disk-based one would.