1This page provides a high-level description of some of the major code
2phases that SeaBIOS transitions through and general information on
3overall code flow.
4
5SeaBIOS code phases
6===================
7
8The SeaBIOS code goes through a few distinct code phases during its
9execution lifecycle. Understanding these code phases can help when
10reading and enhancing the code.
11
12POST phase
13----------
14
15The Power On Self Test (POST) phase is the initialization phase of the
16BIOS. This phase is entered when SeaBIOS first starts execution. The
17goal of the phase is to initialize internal state, initialize external
18interfaces, detect and setup hardware, and to then start the boot
19phase.
20
21On emulators, this phase starts when the CPU starts execution in 16bit
22mode at 0xFFFF0000:FFF0. The emulators map the SeaBIOS binary to this
23address, and SeaBIOS arranges for romlayout.S:reset_vector() to be
24present there. This code calls romlayout.S:entry_post() which then
25calls post.c:handle_post() in 32bit mode.
26
27On coreboot, the build arranges for romlayout.S:entry_elf() to be
28called in 32bit mode. This then calls post.c:handle_post().
29
30On CSM, the build arranges for romlayout.S:entry_csm() to be called
31(in 16bit mode). This then calls csm.c:handle_csm() in 32bit mode.
32Unlike on the emulators and coreboot, the SeaBIOS CSM POST phase is
33orchestrated with UEFI and there are several calls back and forth
34between SeaBIOS and UEFI via handle_csm() throughout the POST
35process.
36
37The POST phase itself has several sub-phases.
38
39* The "preinit" sub-phase: code run prior to [code relocation](Linking overview#Code relocation).
40* The "init" sub-phase: code to initialize internal variables and
41  interfaces.
42* The "setup" sub-phase: code to setup hardware and drivers.
43* The "prepboot" sub-phase: code to finalize interfaces and prepare
44  for the boot phase.
45
46At completion of the POST phase, SeaBIOS invokes an "int 0x19"
47software interrupt in 16bit mode which begins the boot phase.
48
49Boot phase
50----------
51
52The goal of the boot phase is to load the first portion of the
53operating system's boot loader into memory and start execution of that
54boot loader. This phase starts when a software interrupt ("int 0x19"
55or "int 0x18") is invoked. The code flow starts in 16bit mode in
56romlayout.S:entry_19() or romlayout.S:entry_18() which then
57transition to 32bit mode and call boot.c:handle_19() or
58boot.c:handle_18().
59
60The boot phase is technically also part of the "runtime" phase of
61SeaBIOS. It is typically invoked immediately after the POST phase,
62but it can also be invoked by an operating system or be invoked
63multiple times in an attempt to find a valid boot media. Although the
64boot phase C code runs in 32bit mode it does not have write access to
65the 0x0f0000-0x100000 memory region and can not call the various
66malloc_X() calls. See [Memory Model](Memory Model) for
67more information.
68
69Main runtime phase
70------------------
71
72The main runtime phase occurs after the boot phase starts the
73operating system. Once in this phase, the SeaBIOS code may be invoked
74by the operating system using various 16bit and 32bit calls. The goal
75of this phase is to support these legacy calling interfaces and to
76provide compatibility with BIOS standards. There are multiple entry
77points for the BIOS - see the entry_XXX() assembler functions in
78romlayout.S.
79
80Callers use most of these legacy entry points by setting up a
81particular CPU register state, invoking the BIOS, and then inspecting
82the returned CPU register state. To handle this, SeaBIOS will backup
83the current register state into a "struct bregs" (see romlayout.S,
84entryfuncs.S, and bregs.h) on call entry and then pass this struct to
85the C code. The C code can then inspect the register state and modify
86it. The assembler entry functions will then restore the (possibly
87modified) register state from the "struct bregs" on return to the
88caller.
89
90Resume and reboot
91-----------------
92
93As noted above, on emulators SeaBIOS handles the 0xFFFF0000:FFF0
94machine startup execution vector. This vector is also called on
95machine faults and on some machine "resume" events. It can also be
96called (as 0xF0000:FFF0) by software as a request to reboot the
97machine (on emulators, coreboot, and CSM).
98
99The SeaBIOS "resume and reboot" code handles these calls and attempts
100to determine the desired action of the caller. Code flow starts in
10116bit mode in romlayout.S:reset_vector() which calls
102romlayout.S:entry_post() which calls romlayout.S:entry_resume() which
103calls resume.c:handle_resume(). Depending on the request the
104handle_resume() code may transition to 32bit mode.
105
106Technically this code is part of the "runtime" phase, so even though
107parts of it run in 32bit mode it still has the same limitations of the
108runtime phase.
109
110Threads
111=======
112
113Internally SeaBIOS implements a simple cooperative multi-tasking
114system. The system works by giving each "thread" its own stack, and
115the system round-robins between these stacks whenever a thread issues
116a yield() call. This "threading" system may be more appropriately
117described as [coroutines](http://en.wikipedia.org/wiki/Coroutine).
118These "threads" do not run on multiple CPUs and are not preempted, so
119atomic memory accesses and complex locking is not required.
120
121The goal of these threads is to reduce overall boot time by
122parallelizing hardware delays. (For example, by allowing the wait for
123an ATA hard drive to spin-up and respond to commands to occur in
124parallel with the wait for a PS/2 keyboard to respond to a setup
125command.) These hardware setup threads are only available during the
126"setup" sub-phase of the [POST phase](#POST_phase).
127
128The code that implements threads is in stacks.c.
129
130Hardware interrupts
131===================
132
133The SeaBIOS C code always runs with hardware interrupts disabled. All
134of the C code entry points (see romlayout.S) are careful to explicitly
135disable hardware interrupts (via "cli"). Because running with
136interrupts disabled increases interrupt latency, any C code that could
137loop for a significant amount of time (more than about 1 ms) should
138periodically call yield(). The yield() call will briefly enable
139hardware interrupts to occur, then disable interrupts, and then resume
140execution of the C code.
141
142There are two main reasons why SeaBIOS always runs C code with
143interrupts disabled. The first reason is that external software may
144override the default SeaBIOS handlers that are called on a hardware
145interrupt event. Indeed, it is common for DOS based applications to do
146this. These legacy third party interrupt handlers may have
147undocumented expectations (such as stack location and stack size) and
148may attempt to call back into the various SeaBIOS software services.
149Greater compatibility and more reproducible results can be achieved by
150only permitting hardware interrupts at specific points (via yield()
151calls). The second reason is that much of SeaBIOS runs in 32bit mode.
152Attempting to handle interrupts in both 16bit mode and 32bit mode and
153switching between modes to delegate those interrupts is an unneeded
154complexity. Although disabling interrupts can increase interrupt
155latency, this only impacts legacy systems where the small increase in
156interrupt latency is unlikely to be noticeable.
157
158Extra 16bit stack
159=================
160
161SeaBIOS implements 16bit real mode handlers for both hardware
162interrupts and software request "interrupts". In a traditional BIOS,
163these requests would use the caller's stack space. However, the
164minimum amount of space the caller must provide has not been
165standardized and very old DOS programs have been observed to allocate
166very small amounts of stack space (100 bytes or less).
167
168By default, SeaBIOS now switches to its own stack on most 16bit real
169mode entry points. This extra stack space is allocated in ["low
170memory"](Memory Model). It ensures SeaBIOS uses a minimal amount of a
171callers stack (typically no more than 16 bytes) for these legacy
172calls. (More recently defined BIOS interfaces such as those that
173support 16bit protected and 32bit protected mode calls standardize a
174minimum stack size with adequate space, and SeaBIOS generally will not
175use its extra stack in these cases.)
176
177The code to implement this stack "hopping" is in romlayout.S and in
178stacks.c.
179