Kevin O'Connor | f076a3e | 2008-02-25 22:25:15 -0500 | [diff] [blame^] | 1 | This code implements an X86 legacy bios. It is intended to be |
| 2 | compiled using standard gnu tools (eg, gas and gcc). |
| 3 | |
| 4 | To build, one should be able to run "make" in the main directory. The |
| 5 | resulting file "out/rom.bin" contains the processed bios image. |
| 6 | |
| 7 | The code has been successfully compiled with gcc 4.1.2 and gas |
| 8 | 2.17.50.0.18. |
| 9 | |
| 10 | |
| 11 | Overview of files: |
| 12 | |
| 13 | The src/ directory contains the bios source code. The post.c code is |
| 14 | compiled in 32bit mode. The output.c code is compiled twice - once in |
| 15 | 16bit mode and once in 32bit mode. The remaining c files are compiled |
| 16 | in 16bit mode. |
| 17 | |
| 18 | The tools/ directory contains helper utilities for manipulating and |
| 19 | building the final rom. |
| 20 | |
| 21 | The out/ directory is created by the build process - it contains all |
| 22 | temporary and final files. |
| 23 | |
| 24 | |
| 25 | Build overview: |
| 26 | |
| 27 | The 16bit code is compiled via gcc to assembler (file out/blob.16.s). |
| 28 | The gcc "-fwhole-program" option is used to optimize the process so |
| 29 | that gcc can efficiently compile and discard unneeded code. |
| 30 | |
| 31 | This resulting assembler code is pulled into romlayout.S. The gas |
| 32 | option ".code16gcc" is used prior to including the gcc generated |
| 33 | assembler - this option enables gcc to be used to generate valid 16 |
| 34 | bit code. The romlayout.S also defines all the mandatory bios visible |
| 35 | memory locations. |
| 36 | |
| 37 | The post code (post.c) is written in 32bits. The 16bit post vector |
| 38 | (in romlayout.S) transitions the cpu into 32 bit mode before calling |
| 39 | the initialization code in post.c. |
| 40 | |
| 41 | In the last step, the compiled 32 bit code is merged into the 16 bit |
| 42 | code so that one binary file contains both. Currently, both 16bit and |
| 43 | 32bit code will be located in the 64K block at segment 0xf000. |
| 44 | |
| 45 | |
| 46 | GCC 16 bit limitations: |
| 47 | |
| 48 | Although the 16bit code is compiled with gcc, developers need to be |
| 49 | aware of the environment. In particular, global variables _must_ be |
| 50 | treated specially. |
| 51 | |
| 52 | The code has full access to stack variables and general purpose |
| 53 | registers. The entry code in romlayout.S will push the original |
| 54 | registers on the stack before calling the C code and then pop them off |
| 55 | (including any required changes) before returning from the interrupt. |
| 56 | Changes to CS, DS, and ES segment registers in C code is also safe. |
| 57 | Changes to other segment registers (SS, FS, GS) need to be restored |
| 58 | manually. |
| 59 | |
| 60 | Stack variables (and pointers to stack variables) work as they |
| 61 | normally do in standard C code. |
| 62 | |
| 63 | However, variables stored outside the stack need to be accessed via |
| 64 | the GET_VAR and SET_VAR macros. This is due to the 16bit segment |
| 65 | nature of the X86 cpu when it is in "real mode". The C entry code |
| 66 | will set DS and SS to point to the stack segment. Variables not on |
| 67 | the stack need to be accessed via an explicit segment register. |
| 68 | Global constant definitions (those in 0xf000) can be accessed via the |
| 69 | CS segment register. Any other access requires altering one of the |
| 70 | other segment registers (usually ES) and then accessing the variable |
| 71 | via that segment register. |