1Etherboot/NILO i386 initialisation path and external call interface 2=================================================================== 3 41. Background 5 6GCC compiles 32-bit code. It is capable of producing 7position-independent code, but the resulting binary is about 25% 8bigger than the corresponding fixed-position code. Since one main use 9of Etherboot is as firmware to be burned into an EPROM, code size must 10be kept as small as possible. 11 12This means that we want to compile fixed-position code with GCC, and 13link it to have a predetermined start address. The problem then is 14that we must know the address that the code will be loaded to when it 15runs. There are several ways to solve this: 16 171. Pick an address, link the code with this start address, then make 18 sure that the code gets loaded at that location. This is 19 problematic, because we may pick an address that we later end up 20 wanting to use to load the operating system that we're booting. 21 222. Pick an address, link the code with this start address, then set up 23 virtual addressing so that the virtual addresses match the 24 link-time addresses regardless of the real physical address that 25 the code is loaded to. This enables us to relocate Etherboot to 26 the top of high memory, where it will be out of the way of any 27 loading operating system. 28 293. Link the code with a text start address of zero and a data start 30 address also of zero. Use 16-bit real mode and the 31 quasi-position-independence it gives you via segment addressing. 32 Doing this requires that we generate 16-bit code, rather than 33 32-bit code, and restricts us to a maximum of 64kB in each segment. 34 35There are other possible approaches (e.g. including a relocation table 36and code that performs standard dynamic relocation), but the three 37options listed above are probably the best available. 38 39Etherboot can be invoked in a variety of ways (ROM, floppy, as a PXE 40NBP, etc). Several of these ways involve control being passed to 41Etherboot with the CPU in 16-bit real mode. Some will involve the CPU 42being in 32-bit protected mode, and there's an outside chance that 43some may involve the CPU being in 16-bit protected mode. We will 44almost certainly have to effect a CPU mode change in order to reach 45the mode we want to be in to execute the C code. 46 47Additionally, Etherboot may wish to call external routines, such as 48BIOS interrupts, which must be called in 16-bit real mode. When 49providing a PXE API, Etherboot must provide a mechanism for external 50code to call it from 16-bit real mode. 51 52Not all i386 builds of Etherboot will want to make real-mode calls. 53For example, when built for LinuxBIOS rather than the standard PCBIOS, 54no real-mode calls are necessary. 55 56For the ultimate in PXE compatibility, we may want to build Etherboot 57to run permanently in real mode. 58 59There is a wide variety of potential combinations of mode switches 60that we may wish to implement. There are additional complications, 61such as the inability to access a high-memory stack when running in 62real mode. 63 642. Transition libraries 65 66To handle all these various combinations of mode switches, we have 67several "transition" libraries in Etherboot. We also have the concept 68of an "internal" and an "external" environment. The internal 69environment is the environment within which we can execute C code. 70The external environment is the environment of whatever external code 71we're trying to interface to, such as the system BIOS or a PXE NBP. 72 73As well as having a separate addressing scheme, the internal 74environment also has a separate stack. 75 76The transition libraries are: 77 78a) librm 79 80librm handles transitions between an external 16-bit real-mode 81environment and an internal 32-bit protected-mode environment with 82virtual addresses. 83 84b) libkir 85 86libkir handles transitions between an external 16-bit real-mode (or 8716:16 or 16:32 protected-mode) environment and an internal 16-bit 88real-mode (or 16:16 protected-mode) environment. 89 90c) libpm 91 92libpm handles transitions between an external 32-bit protected-mode 93environment with flat physical addresses and an internal 32-bit 94protected-mode environment with virtual addresses. 95 96The transition libraries handle the transitions required when 97Etherboot is started up for the first time, the transitions required 98to execute any external code, and the transitions required when 99Etherboot exits (if it exits). When Etherboot provides a PXE API, 100they also handle the transitions required when a PXE client makes a 101PXE API call to Etherboot. 102 103Etherboot may use multiple transition libraries. For example, an 104Etherboot ELF image does not require librm for its initial transitions 105from prefix to runtime, but may require librm for calling external 106real-mode functions. 107 1083. Setup and initialisation 109 110Etherboot is conceptually divided into the prefix, the decompressor, 111and the runtime image. (For non-compressed images, the decompressor 112is a no-op.) The complete image comprises all three parts and is 113distinct from the runtime image, which exclude the prefix and the 114decompressor. 115 116The prefix does several tasks: 117 118 Load the complete image into memory. (For example, the floppy 119 prefix issues BIOS calls to load the remainder of the complete image 120 from the floppy disk into RAM, and the ISA ROM prefix copies the ROM 121 contents into RAM for faster access.) 122 123 Call the decompressor, if the runtime image is compressed. This 124 decompresses the runtime image. 125 126 Call the runtime image's setup() routine. This is a routine 127 implemented in assembly code which sets up the internal environment 128 so that C code can execute. 129 130 Call the runtime image's arch_initialise() routine. This is a 131 routine implemented in C which does some basic startup tasks, such 132 as initialising the console device, obtaining a memory map and 133 relocating the runtime image to high memory. 134 135 Call the runtime image's arch_main() routine. This records the exit 136 mechanism requested by the prefix and calls main(). (The prefix 137 needs to register an exit mechanism because by the time main() 138 returns, the memory occupied by the prefix has most likely been 139 overwritten.) 140 141When acting as a PXE ROM, the ROM prefix contains an UNDI loader 142routine in addition to its usual code. The UNDI loader performs a 143similar sequence of steps: 144 145 Load the complete image into memory. 146 147 Call the decompressor. 148 149 Call the runtime image's setup() routine. 150 151 Call the runtime image's arch_initialise() routine. 152 153 Call the runtime image's install_pxe_stack() routine. 154 155 Return to caller. 156 157The runtime image's setup() routine will perform the following steps: 158 159 Switch to the internal environment using an appropriate transition 160 library. This will record the parameters of the external 161 environment. 162 163 Set up the internal environment: load a stack, and set up a GDT for 164 virtual addressing if virtual addressing is to be used. 165 166 Switch back to the external environment using the transition 167 library. This will record the parameters of the internal 168 environment. 169 170Once the setup() routine has returned, the internal environment has been 171set up ready for C code to run. The prefix can call C routines using 172a function from the transition library. 173 174The runtime image's arch_initialise() routine will perform the 175following steps: 176 177 Zero the bss 178 179 Initialise the console device(s) and print a welcome message. 180 181 Obtain a memory map via the INT 15,E820 BIOS call or suitable 182 fallback mechanism. [not done if libkir is being used] 183 184 Relocate the runtime image to the top of high memory. [not done if 185 libkir is being used] 186 187 Install librm to base memory. [done only if librm is being used] 188 189 Call initialise(). 190 191 Return to the prefix, setting registers to indicate to the prefix 192 the new location of the transition library, if applicable. Which 193 registers these are is specific to the transition library being 194 used. 195 196Once the arch_initialise() routine has returned, the prefix will 197probably call arch_main(). 198