127 lines
5.2 KiB
ReStructuredText
127 lines
5.2 KiB
ReStructuredText
.. _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 :option:`CONFIG_SRAM_BASE_ADDRESS` and
|
|
:option:`CONFIG_SRAM_SIZE` while the virtual address space is marked by
|
|
:option:`CONFIG_KERNEL_VM_BASE` and :option:`CONFIG_KERNEL_VM_SIZE`.
|
|
Note that :option:`CONFIG_SRAM_OFFSET` controls where the Zephyr kernel
|
|
is being placed in the memory, and its counterpart
|
|
:option:`CONFIG_KERNEL_VM_OFFSET`.
|
|
|
|
Separate Virtual Address Space from Physical Address Space
|
|
==========================================================
|
|
|
|
On 32-bit x86, it is possible to have separate phyiscal 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`) copies the mappings at the top level
|
|
page table such that the same second level tables are used for both
|
|
identity and virutal memory mappings. Later in the boot process,
|
|
the entries for identity mapping at the top level page table is
|
|
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 top level, there is no need to allocate additional
|
|
space for lower level tables in the whole page table structure,
|
|
or else the extra tables become wasted space once unmapped and
|
|
no longer referred. Because of this, 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 top level will be cleared.
|
|
If they are not disjoint, it would clear the entries needed for
|
|
virtual addresses.
|
|
|
|
- If :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 :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.
|
|
|
|
- Due to re-using of second level entries, both
|
|
``CONFIG_SRAM_OFFSET`` and ``CONFIG_KERNEL_VM_OFFSET`` must be of
|
|
same value.
|
|
|
|
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 adderss>]]``, 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.
|
|
|
|
- Default is small page (4KB), supervisor only, read only, and
|
|
execution 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). :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.
|