This page describes the boot prefixes and debugging tips. Debugging a boot prefix can be challenging because most code is assembly and it is not possible to call into gPXE for utility and I/O functions.

How to identify a prefix issue

A crash, hang, or other issue may be prefix-related if it occurs before gPXE prints its banner. If gPXE fails to load then it may be a prefix issue. Odd behavior when exiting gPXE may also be prefix issues.

Overview

The boot prefix is the first code executed when gPXE is started. Its task is to install gPXE into memory and set up the environment in which C code can run. Prefix code is the only part of a gPXE image which is not compressed because it contains the decompressor that is used to load the rest of gPXE.

The x86 boot prefix code is located in arch/i386/prefix/. It consists of a medium-specific prefix assembly file and common prefix code used for all media. For example, the floppy prefix is dskprefix.S and most of the common code is in libprefix.S.

The machine state when gPXE begins running is medium-specific. For example, the floppy prefix starts with a floppy disk boot sector which the BIOS loads at 07c0:0000 in memory.

The medium-specific prefix code:

  1. initializes registers and sets up a stack.
  2. ensures that the raw gPXE image is in memory, for example by reading it off disk.
  3. calls libprefix.S:install to decompress and install gPXE into memory. When this returns the .text16 and .text segments are ready.
  4. transfers execution to the .text16 segment. After this point the prefix segment is never used again.
  5. calls C main() in protected mode. When this returns gPXE has finished executing.
  6. calls libprefix.S:uninstall to clean up before returning to firmware.
  7. returns to firmware to boot the next device.

Most of the work is done in libprefix.S:install. Decompressing and installing gPXE into memory is done in several stages. When memory regions above the first MB need to be accessed, the code switches into protected mode but always switches back to real mode before completing.

Debugging techniques

Debuggers

It is difficult to use debuggers at this early stage of execution because most gPXE functionality is not yet available and the CPU runs in real mode. Modern debuggers may not support real mode well because applications run under protected mode.

If the issue can be reproduced in a virtual machine then it may be possible to use a debugger.

Printing messages

Usually printf()-style debugging is a good approach except there is no printf() function at this stage. Instead consider using:

  • libprefix.S:print_character and related functions. These work in real mode.
  • manually calling int $0x10 ah=0xe to print a character in real mode.

Infinite loops

An infinite loop can be placed along the code path to identify the location of a crash. If the machine hangs on the infinite loop, then the location is being reached. If the machine crashes, then the location is not reached.

1:	/* Hang here for debugging */
	jmp	1b

Reboots

If the issue is a hang then it may not be possible to use an infinite loop to determine where the hang occurs. Instead, a reboot can be used to identify where code goes wrong.

	/* Reboot */
	jmpl	$0xf000, $0xfff0

QR Code
QR Code dev:prefixdebugging (generated for current page)