blob: daa38a9e4af4cc76ce969823769b9c6abc8b6860 [file] [log] [blame]
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05001This code implements an X86 legacy bios. It is intended to be
2compiled using standard gnu tools (eg, gas and gcc).
3
4To build, one should be able to run "make" in the main directory. The
Kevin O'Connor59fead62008-05-10 15:49:20 -04005resulting file "out/bios.bin" contains the processed bios image.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -05006
Kevin O'Connor838f08f2008-03-30 11:07:42 -04007
8Testing of images:
9
10To test the bios under bochs, one will need to instruct bochs to use
11the new bios image. Use the 'romimage' option - for example:
12
Kevin O'Connor59fead62008-05-10 15:49:20 -040013bochs -q 'floppya: 1_44=myfdimage.img' 'romimage: file=out/bios.bin'
Kevin O'Connor838f08f2008-03-30 11:07:42 -040014
15To test under qemu, one will need to create a directory with all the
16bios images and then overwrite the main bios image. For example:
17
18cp /usr/share/qemu/*.bin mybiosdir/
Kevin O'Connor59fead62008-05-10 15:49:20 -040019cp out/bios.bin mybiosdir/
Kevin O'Connorac467be2013-03-17 10:29:06 -040020cp out/*.aml mybiosdir/
Kevin O'Connor838f08f2008-03-30 11:07:42 -040021
22Once this is setup, one can instruct qemu to use the newly created
23directory for rom images. For example:
24
25qemu -L mybiosdir/ -fda myfdimage.img
26
27
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050028Overview of files:
29
Kevin O'Connor838f08f2008-03-30 11:07:42 -040030The src/ directory contains the bios source code. Several of the
31files are compiled twice - once for 16bit mode and once for 32bit
Kevin O'Connor0942e7f2009-06-15 22:27:01 -040032mode. (The build system will remove code that is not needed for a
33particular mode.)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050034
35The tools/ directory contains helper utilities for manipulating and
36building the final rom.
37
38The out/ directory is created by the build process - it contains all
39temporary and final files.
40
41
42Build overview:
43
Kevin O'Connor0afee522009-02-05 20:32:41 -050044The 16bit code is compiled via gcc to assembler (file out/ccode.16.s).
Kevin O'Connor0942e7f2009-06-15 22:27:01 -040045The gcc "-fwhole-program" and "-ffunction-sections -fdata-sections"
46options are used to optimize the process so that gcc can efficiently
47compile and discard unneeded code. (In the code, one can use the
Kevin O'Connor0fdf1932011-10-04 21:12:28 -040048macros 'VISIBLE16' and 'VISIBLE32FLAT' to instruct a symbol to be
Kevin O'Connor0942e7f2009-06-15 22:27:01 -040049outputted in 16bit and 32bit mode respectively.)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050050
51This resulting assembler code is pulled into romlayout.S. The gas
52option ".code16gcc" is used prior to including the gcc generated
Kevin O'Connor838f08f2008-03-30 11:07:42 -040053assembler - this option enables gcc to generate valid 16 bit code.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050054
Kevin O'Connor0fdf1932011-10-04 21:12:28 -040055The post code (post.c) is entered, via the function handle_post(), in
5632bit mode. The 16bit post vector (in romlayout.S) transitions the
57cpu into 32 bit mode before calling the post.c code.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050058
Kevin O'Connor838f08f2008-03-30 11:07:42 -040059In the last step of compilation, the 32 bit code is merged into the 16
60bit code so that one binary file contains both. Currently, both 16bit
Kevin O'Connor0fdf1932011-10-04 21:12:28 -040061and 32bit code will be located in the memory at 0xe0000-0xfffff.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050062
63
64GCC 16 bit limitations:
65
66Although the 16bit code is compiled with gcc, developers need to be
67aware of the environment. In particular, global variables _must_ be
68treated specially.
69
70The code has full access to stack variables and general purpose
71registers. The entry code in romlayout.S will push the original
72registers on the stack before calling the C code and then pop them off
73(including any required changes) before returning from the interrupt.
74Changes to CS, DS, and ES segment registers in C code is also safe.
75Changes to other segment registers (SS, FS, GS) need to be restored
76manually.
77
78Stack variables (and pointers to stack variables) work as they
79normally do in standard C code.
80
81However, variables stored outside the stack need to be accessed via
Kevin O'Connor838f08f2008-03-30 11:07:42 -040082the GET_VAR and SET_VAR macros (or one of the helper macros described
83below). This is due to the 16bit segment nature of the X86 cpu when
84it is in "real mode". The C entry code will set DS and SS to point to
85the stack segment. Variables not on the stack need to be accessed via
Kevin O'Connor0afee522009-02-05 20:32:41 -050086an explicit segment register. Any other access requires altering one
87of the other segment registers (usually ES) and then accessing the
88variable via that segment register.
Kevin O'Connor838f08f2008-03-30 11:07:42 -040089
90There are three low-level ways to access a remote variable:
Kevin O'Connor0afee522009-02-05 20:32:41 -050091GET/SET_VAR, GET/SET_FARVAR, and GET/SET_FLATPTR. The first set takes
Kevin O'Connor838f08f2008-03-30 11:07:42 -040092an explicit segment descriptor (eg, "CS") and offset. The second set
Kevin O'Connor0afee522009-02-05 20:32:41 -050093will take a segment id and offset, set ES to the segment id, and then
Kevin O'Connor838f08f2008-03-30 11:07:42 -040094make the access via the ES segment. The last method is similar to the
Kevin O'Connor0afee522009-02-05 20:32:41 -050095second, except it takes a pointer that would be valid in 32-bit flat
96mode instead of a segment/offset pair.
Kevin O'Connor838f08f2008-03-30 11:07:42 -040097
Kevin O'Connor0afee522009-02-05 20:32:41 -050098Most BIOS variables are stored in global variables, the "BDA", or
99"EBDA" memory areas. Because this is common, three sets of helper
100macros (GET/SET_GLOBAL, GET/SET_BDA, and GET/SET_EBDA) are available
Kevin O'Connor14b255b2013-07-14 14:40:19 -0400101to simplify these accesses. Also, an area in the 0xc0000-0xf0000
102memory range is made available for internal BIOS run-time variables
103that are marked iwth the VARLOW attribute. These variables can then
104be accessed with the GET/SET_LOW macros.
Kevin O'Connor0afee522009-02-05 20:32:41 -0500105
106Global variables defined in the C code can be read in 16bit mode if
Kevin O'Connor14b255b2013-07-14 14:40:19 -0400107the variable declaration is marked with VAR16, VARFSEG, or VAR16FIXED.
108The GET_GLOBAL macro will then allow read access to the variable.
109Global variables are stored in the 0xf000 segment. Because the
110f-segment is marked read-only during run-time, the 16bit code is not
111permitted to change the value of 16bit variables (use of the
112SET_GLOBAL macro from 16bit mode will cause a link error). Code
113running in 32bit mode can not access variables with VAR16, but can
114access variables marked with VARFSEG, VARLOW, VAR16FIXED, or with no
115marking at all. The 32bit code can use the GET/SET_GLOBAL macros, but
116they are not required.
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400117
118
119GCC 16 bit stack limitations:
120
121Another limitation of gcc is its use of 32-bit temporaries. Gcc will
122allocate 32-bits of space for every variable - even if that variable
123is only defined as a 'u8' or 'u16'. If one is not careful, using too
124much stack space can break old DOS applications.
125
126There does not appear to be explicit documentation on the minimum
127stack space available for bios calls. However, Freedos has been
Kevin O'Connor0bb2a442008-04-01 21:09:05 -0400128observed to call into the bios with less than 150 bytes available.
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400129
130Note that the post code and boot code (irq 18/19) do not have a stack
Kevin O'Connor0afee522009-02-05 20:32:41 -0500131limitation because the entry points for these functions transition the
132cpu to 32bit mode and reset the stack to a known state. Only the
133general purpose 16-bit service entry points are affected.
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400134
135There are some ways to reduce stack usage: making sure functions are
136tail-recursive often helps, reducing the number of parameters passed
137to functions often helps, sometimes reordering variable declarations
138helps, inlining of functions can sometimes help, and passing of packed
Kevin O'Connor0afee522009-02-05 20:32:41 -0500139structures can also help. It is also possible to transition to/from
140an extra stack stored in the EBDA using the stack_hop helper function.
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400141
Kevin O'Connor0bb2a442008-04-01 21:09:05 -0400142Some useful stats: the overhead for the entry to a bios handler that
Kevin O'Connor0942e7f2009-06-15 22:27:01 -0400143takes a 'struct bregs' is 42 bytes of stack space (6 bytes from
144interrupt insn, 32 bytes to store registers, and 4 bytes for call
Kevin O'Connor0bb2a442008-04-01 21:09:05 -0400145insn). An entry to an ISR handler without args takes 30 bytes (6 + 20
146+ 4).
147
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400148
149Debugging the bios:
150
151The bios will output information messages to a special debug port.
Kevin O'Connor0fdf1932011-10-04 21:12:28 -0400152Under qemu, one can view these messages by adding '-chardev
153stdio,id=seabios -device isa-debugcon,iobase=0x402,chardev=seabios' to
154the qemu command line. Once this is done, one should see status
155messages on the console.
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400156
157The gdb-server mechanism of qemu is also useful. One can use gdb with
158qemu to debug system images. To use this, add '-s -S' to the qemu
159command line. For example:
160
161qemu -L mybiosdir/ -fda myfdimage.img -s -S
162
163Then, in another session, run gdb with either out/rom16.o (to debug
164bios 16bit code) or out/rom32.o (to debug bios 32bit code). For
165example:
166
167gdb out/rom16.o
168
169Once in gdb, use the command "target remote localhost:1234" to have
170gdb connect to qemu. See the qemu documentation for more information
171on using gdb and qemu in this mode. Note that gdb seems to get
172breakpoints confused when the cpu is in 16-bit real mode. This makes
173stepping through the program difficult (though 'step instruction'
174still works). Also, one may need to set 16bit break points at both
175the cpu address and memory address (eg, break *0x1234 ; break
176*0xf1234).