blob: 8f1bd2081b0433b4b335c639c96f1b0e702d81a3 [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'Connor838f08f2008-03-30 11:07:42 -040020
21Once this is setup, one can instruct qemu to use the newly created
22directory for rom images. For example:
23
24qemu -L mybiosdir/ -fda myfdimage.img
25
26
27The following payloads have been tested:
28
29Freedos - see http://www.freedos.org/ . Useful tests include: booting
30from installation cdrom, installing to hard drive and floppy, making
31sure hard drive and floppy boots then work. It is also useful to take
32the bootable floppy and hard-drive images, write them to an el-torito
33bootable cdrom using the Linux mkisofs utility, and then boot those
34cdrom images.
35
36Linux - useful hard drive image available from
37http://fabrice.bellard.free.fr/qemu/linux-0.2.img.bz2 . It is also
38useful to test standard distribution bootup and live cdroms.
39
40NetBSD - useful hard drive image available from
41http://nopid.free.fr/small.ffs.bz2 . It is also useful to test
42standard distribution installation cdroms.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050043
44
45Overview of files:
46
Kevin O'Connor838f08f2008-03-30 11:07:42 -040047The src/ directory contains the bios source code. Several of the
48files are compiled twice - once for 16bit mode and once for 32bit
Kevin O'Connor0942e7f2009-06-15 22:27:01 -040049mode. (The build system will remove code that is not needed for a
50particular mode.)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050051
52The tools/ directory contains helper utilities for manipulating and
53building the final rom.
54
55The out/ directory is created by the build process - it contains all
56temporary and final files.
57
58
59Build overview:
60
Kevin O'Connor0afee522009-02-05 20:32:41 -050061The 16bit code is compiled via gcc to assembler (file out/ccode.16.s).
Kevin O'Connor0942e7f2009-06-15 22:27:01 -040062The gcc "-fwhole-program" and "-ffunction-sections -fdata-sections"
63options are used to optimize the process so that gcc can efficiently
64compile and discard unneeded code. (In the code, one can use the
65macros 'VISIBLE16' and 'VISIBLE32' to instruct a symbol to be
66outputted in 16bit and 32bit mode respectively.)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050067
68This resulting assembler code is pulled into romlayout.S. The gas
69option ".code16gcc" is used prior to including the gcc generated
Kevin O'Connor838f08f2008-03-30 11:07:42 -040070assembler - this option enables gcc to generate valid 16 bit code.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050071
Kevin O'Connor838f08f2008-03-30 11:07:42 -040072The post code (post.c) is entered, via the function _start(), in 32bit
73mode. The 16bit post vector (in romlayout.S) transitions the cpu into
7432 bit mode before calling the post.c code.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050075
Kevin O'Connor838f08f2008-03-30 11:07:42 -040076In the last step of compilation, the 32 bit code is merged into the 16
77bit code so that one binary file contains both. Currently, both 16bit
78and 32bit code will be located in the 64K block at segment 0xf000.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050079
80
81GCC 16 bit limitations:
82
83Although the 16bit code is compiled with gcc, developers need to be
84aware of the environment. In particular, global variables _must_ be
85treated specially.
86
87The code has full access to stack variables and general purpose
88registers. The entry code in romlayout.S will push the original
89registers on the stack before calling the C code and then pop them off
90(including any required changes) before returning from the interrupt.
91Changes to CS, DS, and ES segment registers in C code is also safe.
92Changes to other segment registers (SS, FS, GS) need to be restored
93manually.
94
95Stack variables (and pointers to stack variables) work as they
96normally do in standard C code.
97
98However, variables stored outside the stack need to be accessed via
Kevin O'Connor838f08f2008-03-30 11:07:42 -040099the GET_VAR and SET_VAR macros (or one of the helper macros described
100below). This is due to the 16bit segment nature of the X86 cpu when
101it is in "real mode". The C entry code will set DS and SS to point to
102the stack segment. Variables not on the stack need to be accessed via
Kevin O'Connor0afee522009-02-05 20:32:41 -0500103an explicit segment register. Any other access requires altering one
104of the other segment registers (usually ES) and then accessing the
105variable via that segment register.
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400106
107There are three low-level ways to access a remote variable:
Kevin O'Connor0afee522009-02-05 20:32:41 -0500108GET/SET_VAR, GET/SET_FARVAR, and GET/SET_FLATPTR. The first set takes
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400109an explicit segment descriptor (eg, "CS") and offset. The second set
Kevin O'Connor0afee522009-02-05 20:32:41 -0500110will take a segment id and offset, set ES to the segment id, and then
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400111make the access via the ES segment. The last method is similar to the
Kevin O'Connor0afee522009-02-05 20:32:41 -0500112second, except it takes a pointer that would be valid in 32-bit flat
113mode instead of a segment/offset pair.
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400114
Kevin O'Connor0afee522009-02-05 20:32:41 -0500115Most BIOS variables are stored in global variables, the "BDA", or
116"EBDA" memory areas. Because this is common, three sets of helper
117macros (GET/SET_GLOBAL, GET/SET_BDA, and GET/SET_EBDA) are available
118to simplify these accesses.
119
120Global variables defined in the C code can be read in 16bit mode if
Kevin O'Connor372e0712009-09-09 09:51:31 -0400121the variable declaration is marked with VAR16, VAR16VISIBLE,
122VAR16EXPORT, or VAR16FIXED. The GET_GLOBAL macro will then allow read
123access to the variable. Global variables are stored in the 0xf000
124segment, and their values are persistent across soft resets. Because
125the f-segment is marked read-only during run-time, the 16bit code is
126not permitted to change the value of 16bit variables (use of the
127SET_GLOBAL macro from 16bit mode will cause a link error). Code
128running in 32bit mode can not access variables with VAR16, but can
129access variables marked with VAR16VISIBLE, VAR16EXPORT, VAR16FIXED, or
130with no marking at all. The 32bit code can use the GET/SET_GLOBAL
131macros, but they are not required.
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400132
133
134GCC 16 bit stack limitations:
135
136Another limitation of gcc is its use of 32-bit temporaries. Gcc will
137allocate 32-bits of space for every variable - even if that variable
138is only defined as a 'u8' or 'u16'. If one is not careful, using too
139much stack space can break old DOS applications.
140
141There does not appear to be explicit documentation on the minimum
142stack space available for bios calls. However, Freedos has been
Kevin O'Connor0bb2a442008-04-01 21:09:05 -0400143observed to call into the bios with less than 150 bytes available.
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400144
145Note that the post code and boot code (irq 18/19) do not have a stack
Kevin O'Connor0afee522009-02-05 20:32:41 -0500146limitation because the entry points for these functions transition the
147cpu to 32bit mode and reset the stack to a known state. Only the
148general purpose 16-bit service entry points are affected.
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400149
150There are some ways to reduce stack usage: making sure functions are
151tail-recursive often helps, reducing the number of parameters passed
152to functions often helps, sometimes reordering variable declarations
153helps, inlining of functions can sometimes help, and passing of packed
Kevin O'Connor0afee522009-02-05 20:32:41 -0500154structures can also help. It is also possible to transition to/from
155an extra stack stored in the EBDA using the stack_hop helper function.
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400156
Kevin O'Connor0bb2a442008-04-01 21:09:05 -0400157Some useful stats: the overhead for the entry to a bios handler that
Kevin O'Connor0942e7f2009-06-15 22:27:01 -0400158takes a 'struct bregs' is 42 bytes of stack space (6 bytes from
159interrupt insn, 32 bytes to store registers, and 4 bytes for call
Kevin O'Connor0bb2a442008-04-01 21:09:05 -0400160insn). An entry to an ISR handler without args takes 30 bytes (6 + 20
161+ 4).
162
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400163
164Debugging the bios:
165
166The bios will output information messages to a special debug port.
167Under qemu, one can view these messages by enabling the '#define
168DEBUG_BIOS' definition in 'qemu/hw/pc.c'. Once this is done (and qemu
169is recompiled), one should see status messages on the console.
170
171The gdb-server mechanism of qemu is also useful. One can use gdb with
172qemu to debug system images. To use this, add '-s -S' to the qemu
173command line. For example:
174
175qemu -L mybiosdir/ -fda myfdimage.img -s -S
176
177Then, in another session, run gdb with either out/rom16.o (to debug
178bios 16bit code) or out/rom32.o (to debug bios 32bit code). For
179example:
180
181gdb out/rom16.o
182
183Once in gdb, use the command "target remote localhost:1234" to have
184gdb connect to qemu. See the qemu documentation for more information
185on using gdb and qemu in this mode. Note that gdb seems to get
186breakpoints confused when the cpu is in 16-bit real mode. This makes
187stepping through the program difficult (though 'step instruction'
188still works). Also, one may need to set 16bit break points at both
189the cpu address and memory address (eg, break *0x1234 ; break
190*0xf1234).