|  | .. _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`. | 
|  |  | 
|  | Separate Virtual Address Space from Physical Address Space | 
|  | ========================================================== | 
|  |  | 
|  | 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. | 
|  |  | 
|  | - 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). :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. |