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