.. _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: ``,[,[,]]``, where: - ```` is the physical address of the mapping. (Required) - ```` is the size of the region to be mapped. (Required) - ```` 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. - ``