diff options
author | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
---|---|---|
committer | Angelos Mouzakitis <a.mouzakitis@virtualopensystems.com> | 2023-10-10 14:33:42 +0000 |
commit | af1a266670d040d2f4083ff309d732d648afba2a (patch) | |
tree | 2fc46203448ddcc6f81546d379abfaeb323575e9 /roms/seabios/docs/Memory_Model.md | |
parent | e02cda008591317b1625707ff8e115a4841aa889 (diff) |
Change-Id: Iaf8d18082d3991dec7c0ebbea540f092188eb4ec
Diffstat (limited to 'roms/seabios/docs/Memory_Model.md')
-rw-r--r-- | roms/seabios/docs/Memory_Model.md | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/roms/seabios/docs/Memory_Model.md b/roms/seabios/docs/Memory_Model.md new file mode 100644 index 000000000..1ebe865c4 --- /dev/null +++ b/roms/seabios/docs/Memory_Model.md @@ -0,0 +1,253 @@ +The SeaBIOS code is required to support multiple x86 CPU memory +models. This requirement impacts the code layout and internal storage +of SeaBIOS. + +x86 Memory Models +================= + +The x86 line of CPUs has evolved over many years. The original 8086 +chip used 16bit pointers and could only address 1 megabyte of memory. +The 80286 CPU still used 16bit pointers, but could address up to 16 +megabytes of memory. The 80386 chips could process 32bit instructions +and could access up to 4 gigabyte of memory. The most recent x86 chips +can process 64bit instructions and access 16 exabytes of ram. + +During the evolution of the x86 CPUs from the 8086 to the 80386 the +BIOS was extended to handle calls in the various modes that the CPU +implemented. + +This section outlines the five different x86 CPU execution and memory +access models that SeaBIOS supports. + +16bit real mode +--------------- + +This mode is a +[segmented](http://en.wikipedia.org/wiki/Memory_segmentation) memory +mode invoked by callers. The CPU defaults to executing 16bit +instructions. Callers typically invoke the BIOS by issuing an "int x" +instruction which causes a software +[interrupt](http://en.wikipedia.org/wiki/Interrupt) that is handled by +the BIOS. The SeaBIOS code also handles hardware interrupts in this +mode. SeaBIOS can only access the first 1 megabyte of memory in this +mode, but it can access any part of that first megabyte. + +16bit bigreal mode +------------------ + +This mode is a segmented memory mode that is used for [option +roms](http://en.wikipedia.org/wiki/Option_ROM). The CPU defaults to +executing 16bit instructions and segmented memory accesses are still +used. However, the segment limits are increased so that the entire +first 4 gigabytes of memory is fully accessible. Callers can invoke +all the [16bit real mode](#16bit_real_mode) functions while in this +mode and can also invoke the Post Memory Manager (PMM) functions that +are available during option rom execution. + +16bit protected mode +-------------------- + +CPU execution in this mode is similar to [16bit real +mode](#16bit_real_mode). The CPU defaults to executing 16bit +instructions. However, each segment register indexes a "descriptor +table", and it is difficult or impossible to know what the physical +address of each segment is. Generally speaking, the BIOS can only +access code and data in the f-segment. The PCIBIOS, APM BIOS, and PNP +BIOS all have documented 16bit protected mode entry points. + +Some old code may attempt to invoke the standard [16bit real +mode](#16bit_real_mode) entry points while in 16bit protected +mode. The PCI BIOS specification explicitly requires that the legacy +"int 1a" real mode entry point support 16bit protected mode calls if +they are for the PCI BIOS. Callers of other legacy entry points in +protected mode have not been observed and SeaBIOS does not support +them. + +32bit segmented mode +-------------------- + +In this mode the processor runs in 32bit mode, but the segment +registers may have a limit and may have a non-zero offset. In effect, +this mode has all of the limitations of [16bit protected +mode](#16bit_protected_mode) - the main difference between the modes +is that the processor defaults to executing 32bit instructions. In +addition to these limitations, callers may also run the SeaBIOS code +at varying virtual addresses and so the code must support code +relocation. The PCI BIOS specification and APM BIOS specification +define 32bit segmented mode interfaces. + +32bit flat mode +--------------- + +In this mode the processor defaults to executing 32bit instructions, +and all segment registers have an offset of zero and allow access to +the entire first 4 gigabytes of memory. This is the only "sane" mode +for 32bit code - modern compilers and modern operating systems will +generally only support this mode (when running 32bit code). +Ironically, it's the only mode that is not strictly required for a +BIOS to support. SeaBIOS uses this mode internally to support the POST +and BOOT [phases of execution](Execution and code flow). + +code16gcc +========= + +In order to produce code that can run when the processor is in a 16bit +mode, SeaBIOS uses the +[binutils](http://en.wikipedia.org/wiki/GNU_Binutils) ".code16gcc" +assembler flag. This instructs the assembler to emit extra prefix +opcodes so that the 32bit code produced by +[gcc](http://en.wikipedia.org/wiki/GNU_Compiler_Collection) will run +even when the processor is in 16bit mode. Note that gcc always +produces 32bit code - it does not know about the ".code16gcc" flag and +does not know that the code will run in a 16bit mode. + +SeaBIOS uses the same code for all of the 16bit modes ([16bit real +mode](#16bit_real_mode), [16bit bigreal mode](#16bit_bigreal_mode), +and [16bit protected mode](#16bit_protected_mode)) and that code is +assembled using ".code16gcc". SeaBIOS is careful to use segment +registers properly so that the same code can run in the different +16bit modes that it needs to support. + +C code mode flags +================= + +Two compile time flags are available to determine the memory model the +code is intended for: MODE16 and MODESEGMENT. When compiling for the +16 bit modes, MODE16 is true and MODESEGMENT is true. In 32bit +segmented mode, MODE16 is false and MODESEGMENT is true. In 32bit flat +mode both MODE16 and MODESEGMENT are false. + +Common memory used at run-time +============================== + +There are several memory areas that the SeaBIOS "runtime" +[phase](Execution and code flow) makes use of: + +* 0x000000-0x000400: Interrupt descriptor table (IDT). This area + defines 256 interrupt vectors as defined by the Intel CPU + specification for 16bit irq handlers. This area is read/writable at + runtime and can be accessed from 16bit real mode and 16bit bigreal + mode calls. SeaBIOS only uses this area to maintain compatibility + with legacy systems. + +* 0x000400-0x000500: BIOS Data Area (BDA). This area contains various + legacy flags and attributes. The area is read/writable at runtime + and can be accessed from 16bit real mode and 16bit bigreal mode + calls. SeaBIOS only uses this area to maintain compatibility with + legacy systems. + +* 0x09FC00-0x0A0000 (typical): Extended BIOS Data Area (EBDA). This + area contains a few legacy flags and attributes. The area is + typically located at 0x9FC00, but it can be moved by option roms, by + legacy operating systems, and by SeaBIOS if + CONFIG_MALLOC_UPPERMEMORY is not set. Its actual location is + determined by a pointer in the BDA. The area is read/writable at + runtime and can be accessed from 16bit real mode and 16bit bigreal + mode calls. SeaBIOS only uses this area to maintain compatibility + with legacy systems. + +* 0x0E0000-0x0F0000 (typical): "low" memory. This area is used for + custom read/writable storage internal to SeaBIOS. The area is + read/writable at runtime and can be accessed from 16bit real mode + and 16bit bigreal mode calls. The area is typically located at the + end of the e-segment, but the build may position it anywhere in the + 0x0C0000-0x0F0000 region. However, if CONFIG_MALLOC_UPPERMEMORY is + not set, then this region is between 0x090000-0x0A0000. Space is + allocated in this region by either marking a global variable with + the "VARLOW" flag or by calling malloc_low() during + initialization. The area can be grown dynamically (via malloc_low), + but it will never exceed 64K. + +* 0x0F0000-0x100000: The BIOS segment. This area is used for both + runtime code and static variables. Space is allocated in this region + by either marking a global variable with VAR16, one of the VARFSEG + flags, or by calling malloc_fseg() during initialization. The area + is read-only at runtime and can be accessed from 16bit real mode, + 16bit bigreal mode, 16bit protected mode, and 32bit segmented mode + calls. + +All of the above areas are also read/writable during the SeaBIOS +initialization phase and are accessible when in 32bit flat mode. + +Segmented mode memory access +============================ + +The assembler entry functions for segmented mode calls (all modes +except [32bit flat mode](#32bit_flat_mode)) will arrange +to set the data segment (%ds) to be the same as the stack segment +(%ss) before calling any C code. This permits all C variables located +on the stack and C pointers to data located on the stack to work as +normal. + +However, all code running in segmented mode must wrap non-stack memory +accesses in special macros. These macros ensure the correct segment +register is used. Failure to use the correct macro will result in an +incorrect memory access that will likely cause hard to find errors. + +There are three low-level memory access macros: + +* GET_VAR / SET_VAR : Accesses a variable using the specified segment + register. This isn't typically used directly by C code. + +* GET_FARVAR / SET_FARVAR : Assigns the extra segment (%es) to the + given segment id and then performs the given memory access via %es. + +* GET_FLATPTR / SET_FLATPTR : These macros take a 32bit pointer, + construct a segment/offset pair valid in real mode, and then perform + the given access. These macros must not be used in 16bit protected + mode or 32bit segmented mode. + +Since most memory accesses are to [common memory used at +run-time](#Common_memory_used_at_run-time), several helper +macros are also available. + +* GET_IDT / SET_IDT : Access the interrupt descriptor table (IDT). + +* GET_BDA / SET_BDA : Access the BIOS Data Area (BDA). + +* GET_EBDA / SET_EBDA : Access the Extended BIOS Data Area (EBDA). + +* GET_LOW / SET_LOW : Access internal variables marked with + VARLOW. (There are also related macros GET_LOWFLAT / SET_LOWFLAT for + accessing storage allocated with malloc_low.) + +* GET_GLOBAL : Access internal variables marked with the VAR16 or + VARFSEG flags. (There is also the related macro GET_GLOBALFLAT for + accessing storage allocated with malloc_fseg.) + +Memory available during initialization +====================================== + +During the POST [phase](Execution and code flow) the code +can fully access the first 4 gigabytes of memory. However, memory +accesses are generally limited to the [common memory used at +run-time](#Common_memory_used_at_run-time) and areas +allocated at runtime via one of the malloc calls: + +* malloc_high : Permanent high-memory zone. This area is used for + custom read/writable storage internal to SeaBIOS. The area is + located at the top of the first 4 gigabytes of ram. It is commonly + used for storing standard tables accessed by the operating system at + runtime (ACPI, SMBIOS, and MPTable) and for DMA buffers used by + hardware drivers. The area is read/writable at runtime and an entry + in the e820 memory map is used to reserve it. When running on an + emulator that has only 1 megabyte of ram this zone will be empty. + +* malloc_tmphigh : Temporary high-memory zone. This area is used for + custom read/writable storage during the SeaBIOS initialization + phase. The area generally starts after the first 1 megabyte of ram + (0x100000) and ends prior to the Permanent high-memory zone. When + running on an emulator that has only 1 megabyte of ram this zone + will be empty. The area is not reserved from the operating system, + so it must not be accessed after the SeaBIOS initialization phase. + +* malloc_tmplow : Temporary low-memory zone. This area is used for + custom read/writable storage during the SeaBIOS initialization + phase. The area resides between 0x07000-0x90000. The area is not + reserved from the operating system and by specification it is + required to be zero'd at the end of the initialization phase. + +The "tmplow" and "tmphigh" regions are only available during the +initialization phase. Any access (either read or write) after +completion of the initialization phase can result in difficult to find +errors. |