doc/hardware/arch/x86.rst
.. _x86_developer_guide:
x86 Developer Guide ###################
Overview
This page contains information on certain aspects when developing for x86-based platforms.
Virtual Memory
During very early boot, page tables are loaded so technically the kernel
is executing in virtual address space. By default, physical and virtual
memory are identity mapped and thus giving the appearance of execution
taking place in physical address space. The physical address space is
marked by kconfig :kconfig:option:CONFIG_SRAM_BASE_ADDRESS and
:kconfig:option:CONFIG_SRAM_SIZE while the virtual address space is marked by
:kconfig:option:CONFIG_KERNEL_VM_BASE and :kconfig:option:CONFIG_KERNEL_VM_SIZE.
Note that :kconfig:option:CONFIG_SRAM_OFFSET controls where the Zephyr kernel
is being placed in the memory, and its counterpart
:kconfig:option:CONFIG_KERNEL_VM_OFFSET.
On 32-bit x86, it is possible to have separate physical and virtual
address space. Code and data are linked in virtual address space,
but are still loaded in physical memory. However, during boot, code
and data must be available and also addressable in physical address
space before vm_enter inside :file:arch/x86/core/ia32/crt0.S.
After vm_enter, code execution is done via virtual addresses
and data can be referred via their virtual addresses. This is
possible as the page table generation script
(:file:arch/x86/gen_mmu.py) identity maps the physical addresses
at the page directory level, in addition to mapping virtual addresses
to the physical memory. Later in the boot process,
the entries for identity mapping at the page directory level are
cleared in :c:func:z_x86_mmu_init(), effectively removing
the identity mapping of physical memory. This unmapping must be done
for userspace isolation or else they would be able to access
restricted memory via physical addresses. Since the identity mapping
is done at the page directory level, there is no need to allocate
additional space for the page table. However, additional space may
still be required for additional page directory table.
There are restrictions on where virtual address space can be:
Physical and virtual address spaces must be disjoint. This is required as the entries in page directory table will be cleared. If they are not disjoint, it would clear the entries needed for virtual addresses.
If :kconfig:option:CONFIG_X86_PAE is enabled (=y), each address space
must reside in their own 1GB region, due to each entry of PDP
(Page Directory Pointer) covers 1GB of memory. For example:
Assuming CONFIG_SRAM_OFFSET and CONFIG_KERNEL_VM_OFFSET
are both 0x0.
CONFIG_SRAM_BASE_ADDRESS == 0x00000000 and
CONFIG_KERNEL_VM_BASE = 0x40000000 is valid, while
CONFIG_SRAM_BASE_ADDRESS == 0x00000000 and
CONFIG_KERNEL_VM_BASE = 0x20000000 is not.
If :kconfig:option:CONFIG_X86_PAE is disabled (=n), each address space
must reside in their own 4MB region, due to each entry of PD
(Page Directory) covers 4MB of memory.
Both CONFIG_SRAM_BASE_ADDRESS and CONFIG_KERNEL_VM_BASE
must also align with the starting addresses of targeted regions.
Specifying Additional Memory Mappings at Build Time
The page table generation script (:file:arch/x86/gen_mmu.py) generates
the necessary multi-level page tables for code execution and data access
using the kernel image produced by the first linker pass. Additional
command line arguments can be passed to the script to generate additional
memory mappings. This is useful for static mappings and/or device MMIO
access during very early boot. To pass extra command line arguments to
the script, populate a CMake list named X86_EXTRA_GEN_MMU_ARGUMENTS
in the board configuration file. Here is an example:
.. code-block:: cmake
set(X86_EXTRA_GEN_MMU_ARGUMENTS --map 0xA0000000,0x2000 --map 0x80000000,0x400000,LWUX,0xB0000000)
The argument --map takes the following value:
<physical address>,<size>[,<flags:LUWX>[,<virtual address>]], where:
<physical address> is the physical address of the mapping. (Required)
<size> is the size of the region to be mapped. (Required)
<flags> is the flag associated with the mapping: (Optional)
L: Large page at the page directory level.
U: Allow userspace access.
W: Read/write.
X: Allow execution.
D: Cache disabled.
<virtual address is the virtual address of the mapping. (Optional)
Note that specifying additional memory mappings requires larger storage
space for the pre-allocated page tables (both kernel and per-domain
tables). :kconfig:option:CONFIG_X86_EXTRA_PAGE_TABLE_PAGES is needed to
specify how many more memory pages to be reserved for the page tables.
If the needed space is not exactly the same as required space,
the gen_mmu.py script will print out a message indicating what
needs to be the value for the kconfig.