blob: fe5f601dd6bc1c0215db1240580dd30f9548b53c [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).
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 -04007The build requires gcc v4.1 or later. Some buggy versions of gcc have
8issues with the '-combine' compiler option - in particular, recent
9versions of Ubuntu are affected. One can use "make AVOIDCOMBINE=1" to
10get around this.
13Testing of images:
15To test the bios under bochs, one will need to instruct bochs to use
16the new bios image. Use the 'romimage' option - for example:
Kevin O'Connor59fead62008-05-10 15:49:20 -040018bochs -q 'floppya: 1_44=myfdimage.img' 'romimage: file=out/bios.bin'
Kevin O'Connor838f08f2008-03-30 11:07:42 -040019
20To test under qemu, one will need to create a directory with all the
21bios images and then overwrite the main bios image. For example:
23cp /usr/share/qemu/*.bin mybiosdir/
Kevin O'Connor59fead62008-05-10 15:49:20 -040024cp out/bios.bin mybiosdir/
Kevin O'Connor838f08f2008-03-30 11:07:42 -040025
26Once this is setup, one can instruct qemu to use the newly created
27directory for rom images. For example:
29qemu -L mybiosdir/ -fda myfdimage.img
32The following payloads have been tested:
34Freedos - see . Useful tests include: booting
35from installation cdrom, installing to hard drive and floppy, making
36sure hard drive and floppy boots then work. It is also useful to take
37the bootable floppy and hard-drive images, write them to an el-torito
38bootable cdrom using the Linux mkisofs utility, and then boot those
39cdrom images.
41Linux - useful hard drive image available from
42 . It is also
43useful to test standard distribution bootup and live cdroms.
45NetBSD - useful hard drive image available from
46 . It is also useful to test
47standard distribution installation cdroms.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050048
50Overview of files:
Kevin O'Connor838f08f2008-03-30 11:07:42 -040052The src/ directory contains the bios source code. Several of the
53files are compiled twice - once for 16bit mode and once for 32bit
Kevin O'Connor0bb2a442008-04-01 21:09:05 -040054mode. (The gcc compile option '-fwhole-program' is used to remove
55code that is not needed for a particular mode.)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050056
57The tools/ directory contains helper utilities for manipulating and
58building the final rom.
60The out/ directory is created by the build process - it contains all
61temporary and final files.
64Build overview:
66The 16bit code is compiled via gcc to assembler (file out/blob.16.s).
67The gcc "-fwhole-program" option is used to optimize the process so
Kevin O'Connor0bb2a442008-04-01 21:09:05 -040068that gcc can efficiently compile and discard unneeded code. (In the
69code, one can use the macros 'VISIBLE16' and 'VISIBLE32' to instruct a
70symbol to be outputted in 16bit and 32bit mode respectively.)
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050071
72This resulting assembler code is pulled into romlayout.S. The gas
73option ".code16gcc" is used prior to including the gcc generated
Kevin O'Connor838f08f2008-03-30 11:07:42 -040074assembler - this option enables gcc to generate valid 16 bit code.
75The romlayout.S also defines all the mandatory bios visible memory
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050077
Kevin O'Connor838f08f2008-03-30 11:07:42 -040078The post code (post.c) is entered, via the function _start(), in 32bit
79mode. The 16bit post vector (in romlayout.S) transitions the cpu into
8032 bit mode before calling the post.c code.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050081
Kevin O'Connor838f08f2008-03-30 11:07:42 -040082In the last step of compilation, the 32 bit code is merged into the 16
83bit code so that one binary file contains both. Currently, both 16bit
84and 32bit code will be located in the 64K block at segment 0xf000.
Kevin O'Connorf076a3e2008-02-25 22:25:15 -050085
87GCC 16 bit limitations:
89Although the 16bit code is compiled with gcc, developers need to be
90aware of the environment. In particular, global variables _must_ be
91treated specially.
93The code has full access to stack variables and general purpose
94registers. The entry code in romlayout.S will push the original
95registers on the stack before calling the C code and then pop them off
96(including any required changes) before returning from the interrupt.
97Changes to CS, DS, and ES segment registers in C code is also safe.
98Changes to other segment registers (SS, FS, GS) need to be restored
101Stack variables (and pointers to stack variables) work as they
102normally do in standard C code.
104However, variables stored outside the stack need to be accessed via
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400105the GET_VAR and SET_VAR macros (or one of the helper macros described
106below). This is due to the 16bit segment nature of the X86 cpu when
107it is in "real mode". The C entry code will set DS and SS to point to
108the stack segment. Variables not on the stack need to be accessed via
109an explicit segment register. Global constants (loaded into 0xf000)
110can be accessed via the CS segment register. Any other access
111requires altering one of the other segment registers (usually ES) and
112then accessing the variable via that segment register.
114There are three low-level ways to access a remote variable:
115GET/SET_VAR, GET/SET_FARVAR, and GET/SET_FARPTR. The first set takes
116an explicit segment descriptor (eg, "CS") and offset. The second set
117will take a segment id and offset, set ES to the segment, and then
118make the access via the ES segment. The last method is similar to the
119second, except it takes a pointer that would be valid in 32-bit mode
120instead of a segment/offset pair.
122Most BIOS variables are stored in the "BDA" or "EBDA" memory areas.
123Because this is common, two sets of helper macros (GET/SET_BDA and
124GET/SET_EBDA) are available to simplify these accesses.
127GCC 16 bit stack limitations:
129Another limitation of gcc is its use of 32-bit temporaries. Gcc will
130allocate 32-bits of space for every variable - even if that variable
131is only defined as a 'u8' or 'u16'. If one is not careful, using too
132much stack space can break old DOS applications.
134There does not appear to be explicit documentation on the minimum
135stack space available for bios calls. However, Freedos has been
Kevin O'Connor0bb2a442008-04-01 21:09:05 -0400136observed to call into the bios with less than 150 bytes available.
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400137
138Note that the post code and boot code (irq 18/19) do not have a stack
139limitation because the entry points for these functions reset the
140stack to a known state. Only the general purpose 16-bit service entry
141points are affected.
143There are some ways to reduce stack usage: making sure functions are
144tail-recursive often helps, reducing the number of parameters passed
145to functions often helps, sometimes reordering variable declarations
146helps, inlining of functions can sometimes help, and passing of packed
147structures can also help.
Kevin O'Connor0bb2a442008-04-01 21:09:05 -0400149Some useful stats: the overhead for the entry to a bios handler that
150takes a 'struct bregs' is 38 bytes of stack space (6 bytes from
151interrupt insn, 28 bytes to store registers, and 4 bytes for call
152insn). An entry to an ISR handler without args takes 30 bytes (6 + 20
153+ 4).
Kevin O'Connor838f08f2008-03-30 11:07:42 -0400155
156Debugging the bios:
158The bios will output information messages to a special debug port.
159Under qemu, one can view these messages by enabling the '#define
160DEBUG_BIOS' definition in 'qemu/hw/pc.c'. Once this is done (and qemu
161is recompiled), one should see status messages on the console.
163The gdb-server mechanism of qemu is also useful. One can use gdb with
164qemu to debug system images. To use this, add '-s -S' to the qemu
165command line. For example:
167qemu -L mybiosdir/ -fda myfdimage.img -s -S
169Then, in another session, run gdb with either out/rom16.o (to debug
170bios 16bit code) or out/rom32.o (to debug bios 32bit code). For
173gdb out/rom16.o
175Once in gdb, use the command "target remote localhost:1234" to have
176gdb connect to qemu. See the qemu documentation for more information
177on using gdb and qemu in this mode. Note that gdb seems to get
178breakpoints confused when the cpu is in 16-bit real mode. This makes
179stepping through the program difficult (though 'step instruction'
180still works). Also, one may need to set 16bit break points at both
181the cpu address and memory address (eg, break *0x1234 ; break