kernel/memory_management/virtual_memory.html · kernel/memory_management/virtual_memory.rst 공식 원문 ↗

Zephyr 3.7.0 · Kernel · Memory Management

가상 메모리

Page-aligned virtual address space에 kernel image와 anonymous memory를 mapping하고 permission·cache·paging 동작을 제어합니다.

Official pathkernel/memory_management/virtual_memory.html
Source filekernel/memory_management/virtual_memory.rst
Source versionZephyr 3.7.0
TranslationFull · reviewed

본문 기준: Zephyr 3.7.0 LTS3 · 이후 유지보수 패치는 별도입니다.

Part 1

요약·해설

Embedded 기본은 demand paging 없는 1:1 kernel image mapping이며, 동적 mapping에는 access flag와 앞뒤 guard page를 적용합니다.

Zephyr virtual address space의 경계와 mapping 성장 방향
K_MEM_VIRT_RAM_START

Virtual address space 시작 · page aligned

Undefined VM

Architecture별 reserved 영역

K_MEM_KERNEL_VIRT_START

Main kernel image mapping 시작

Kernel image

code · rodata · data · bss · noinit

K_MEM_VM_FREE_START

동적 mapping에 쓸 수 있는 낮은 경계

Unused · Available VM

새 mapping이 높은 주소 쪽 시작점에서 아래 방향으로 늘어남

Mapping stack

여러 mapped region과 각 guard page

K_MEM_VM_RESERVED

Demand paging 등 kernel 특수 용도 virtual page

K_MEM_VIRT_RAM_END

START + SIZE · virtual space 끝

Requirement

MMU

Default

1:1 kernel image

Anonymous

page + guards

Part 2

접을 수 있는 영어 원문 전체

영어 원문 전체 펼치기
원문 SHA-256 C3DC06FDE4B6B3FB48CFB0A56CF7631C2CA41D05C08230BA5DFFF059BCD08D2C
.. _memory_management_api_virtual_memory:

Virtual Memory
##############

Virtual memory (VM) in Zephyr provides developers with the ability to fine tune
access to memory. To utilize virtual memory, the platform must support
Memory Management Unit (MMU) and it must be enabled in the build. Due to
the target of Zephyr mainly being embedded systems, virtual memory
support in Zephyr differs a bit from that in traditional operating
systems:

Mapping of Kernel Image
  Default is to do 1:1 mapping for the kernel image (including code and data)
  between physical and virtual memory address spaces, if demand paging
  is not enabled. Deviation from this requires careful manipulation of
  linker script.

Secondary Storage
  Basic virtual memory support does not utilize secondary storage to
  extend usable memory. The maximum usable memory is the same as
  the physical memory.

  * :ref:`memory_management_api_demand_paging` enables utilizing
    secondary storage as a backing store for virtual memory, thus
    allowing larger usable memory than the available physical memory.
    Note that demand paging needs to be explicitly enabled.

  * Although the virtual memory space can be larger than physical
    memory space, without enabling demand paging, all virtually
    mapped memory must be backed by physical memory.


Kconfigs
********

Required
========

These are the Kconfigs that need to be enabled or defined for kernel to support
virtual memory.

* :kconfig:option:`CONFIG_MMU`: must be enabled for virtual memory support in
  kernel.

* :kconfig:option:`CONFIG_MMU_PAGE_SIZE`: size of a memory page. Default is 4KB.

* :kconfig:option:`CONFIG_KERNEL_VM_BASE`: base address of virtual address space.

* :kconfig:option:`CONFIG_KERNEL_VM_SIZE`: size of virtual address space.
  Default is 8MB.

* :kconfig:option:`CONFIG_KERNEL_VM_OFFSET`: kernel image starts at this offset
  from :kconfig:option:`CONFIG_KERNEL_VM_BASE`.

Optional
========

* :kconfig:option:`CONFIG_KERNEL_DIRECT_MAP`: permits 1:1 mappings between
  virtual and physical addresses, instead of kernel choosing addresses within
  the virtual address space. This is useful for mapping device MMIO regions for
  more precise access control.


Memory Map Overview
*******************

This is an overview of the memory map of the virtual memory address space.
Note that the ``Z_*`` macros, which are used in code, may have different
meanings depending on architecture and Kconfigs, which will be explained
below.

.. code-block:: none
   :emphasize-lines: 1, 3, 9, 22, 24

   +--------------+ <- K_MEM_VIRT_RAM_START
   | Undefined VM | <- architecture specific reserved area
   +--------------+ <- K_MEM_KERNEL_VIRT_START
   | Mapping for  |
   | main kernel  |
   | image        |
   |              |
   |              |
   +--------------+ <- K_MEM_VM_FREE_START
   |              |
   | Unused,      |
   | Available VM |
   |              |
   |..............| <- grows downward as more mappings are made
   | Mapping      |
   +--------------+
   | Mapping      |
   +--------------+
   | ...          |
   +--------------+
   | Mapping      |
   +--------------+ <- memory mappings start here
   | Reserved     | <- special purpose virtual page(s) of size K_MEM_VM_RESERVED
   +--------------+ <- K_MEM_VIRT_RAM_END

* ``K_MEM_VIRT_RAM_START`` is the beginning of the virtual memory address space.
  This needs to be page aligned. Currently, it is the same as
  :kconfig:option:`CONFIG_KERNEL_VM_BASE`.

* ``K_MEM_VIRT_RAM_SIZE`` is the size of the virtual memory address space.
  This needs to be page aligned. Currently, it is the same as
  :kconfig:option:`CONFIG_KERNEL_VM_SIZE`.

* ``K_MEM_VIRT_RAM_END`` is simply (``K_MEM_VIRT_RAM_START`` + ``K_MEM_VIRT_RAM_SIZE``).

* ``K_MEM_KERNEL_VIRT_START`` is the same as ``z_mapped_start`` specified in the linker
  script. This is the virtual address of the beginning of the kernel image at
  boot time.

* ``K_MEM_KERNEL_VIRT_END`` is the same as ``z_mapped_end`` specified in the linker
  script. This is the virtual address of the end of the kernel image at boot time.

* ``K_MEM_VM_FREE_START`` is the beginning of the virtual address space where addresses
  can be allocated for memory mapping. This depends on whether
  :kconfig:option:`CONFIG_ARCH_MAPS_ALL_RAM` is enabled.

  * If it is enabled, which means all physical memory are mapped in virtual
    memory address space, and it is the same as
    (:kconfig:option:`CONFIG_SRAM_BASE_ADDRESS` + :kconfig:option:`CONFIG_SRAM_SIZE`).

  * If it is disabled, ``K_MEM_VM_FREE_START`` is the same ``K_MEM_KERNEL_VIRT_END`` which
    is the end of the kernel image.

* ``K_MEM_VM_RESERVED`` is an area reserved to support kernel functions. For example,
  some addresses are reserved to support demand paging.


Virtual Memory Mappings
***********************

Setting up Mappings at Boot
===========================

In general, most supported architectures set up the memory mappings at boot as
following:

* ``.text`` section is read-only and executable. It is accessible in
  both kernel and user modes.

* ``.rodata`` section is read-only and non-executable. It is accessible
  in both kernel and user modes.

* Other kernel sections, such as ``.data``, ``.bss`` and ``.noinit``, are
  read-write and non-executable. They are only accessible in kernel mode.

  * Stacks for user mode threads are automatically granted read-write access
    to their corresponding user mode threads during thread creation.

  * Global variables, by default, are not accessible to user mode threads.
    Refer to :ref:`Memory Domains and Partitions<memory_domain>` on how to
    use global variables in user mode threads, and on how to share data
    between user mode threads.

Caching modes for these mappings are architecture specific. They can be
none, write-back, or write-through.

Note that SoCs have their own additional mappings required to boot where
these mappings are defined under their own SoC configurations. These mappings
usually include device MMIO regions needed to setup the hardware.


Mapping Anonymous Memory
========================

The unused physical memory can be mapped in virtual address space on demand.
This is conceptually similar to memory allocation from heap, but these
mappings must be aligned on page size and have finer access control.

* :c:func:`k_mem_map` can be used to map unused physical memory:

  * The requested size must be multiple of page size.

  * The address returned is inside the virtual address space between
    ``K_MEM_VM_FREE_START`` and ``K_MEM_VIRT_RAM_END``.

  * The mapped region is not guaranteed to be physically contiguous in memory.

  * Guard pages immediately before and after the mapped virtual region are
    automatically allocated to catch access issue due to buffer underrun
    or overrun.

* The mapped region can be unmapped (i.e. freed) via :c:func:`k_mem_unmap`:

  * Caution must be exercised to give the pass the same region size to
    both :c:func:`k_mem_map` and :c:func:`k_mem_unmap`. The unmapping
    function does not check if it is a valid mapped region before unmapping.


API Reference
*************

.. doxygengroup:: kernel_memory_management

Part 3

한국어 전문 번역

Zephyr virtual memory(VM)는 developer가 memory access를 세밀하게 조절하게 합니다. Platform이 MMU(Memory Management Unit)를 지원해야 하고 build에서 활성화해야 합니다. Embedded system을 주 대상으로 하므로 전통적인 범용 OS의 VM과 몇 가지 차이가 있습니다.

Zephyr VM의 기본 성격

Kernel image mapping: Demand paging이 꺼져 있으면 code와 data를 포함한 kernel image의 physical·virtual address를 기본적으로 1:1 mapping합니다. 다른 배치를 쓰려면 linker script를 신중하게 조정해야 합니다.

Secondary storage: 기본 VM은 usable memory를 늘리려고 secondary storage를 사용하지 않으므로 최대 usable memory는 physical memory와 같습니다. Demand paging을 명시적으로 활성화하면 secondary storage를 backing store로 사용해 physical RAM보다 큰 memory를 운용할 수 있습니다. Virtual address space 자체가 더 크더라도 demand paging이 없으면 mapping된 모든 virtual memory를 실제 physical memory가 뒷받침해야 합니다.

Kconfig

필수

  • CONFIG_MMU: kernel VM 지원을 활성화합니다.
  • CONFIG_MMU_PAGE_SIZE: memory page 크기이며 기본값은 4KB입니다.
  • CONFIG_KERNEL_VM_BASE: virtual address space base입니다.
  • CONFIG_KERNEL_VM_SIZE: virtual address space 크기이며 기본값은 8MB입니다.
  • CONFIG_KERNEL_VM_OFFSET: kernel image가 CONFIG_KERNEL_VM_BASE에서 떨어진 offset입니다.

선택

CONFIG_KERNEL_DIRECT_MAP은 kernel이 virtual space 안에서 별도 주소를 고르는 대신 virtual·physical 1:1 mapping을 허용합니다. Device MMIO region을 더 정밀한 access control로 mapping할 때 유용합니다.

Memory map 개요

다음 구조화 도식은 virtual address space 전체를 낮은 주소에서 높은 주소 순으로 보여줍니다. Code에서 쓰는 Z_* macro는 architecture와 Kconfig에 따라 의미가 달라질 수 있습니다.

Zephyr virtual address space의 경계와 mapping 성장 방향
K_MEM_VIRT_RAM_START

Virtual address space 시작 · page aligned

Undefined VM

Architecture별 reserved 영역

K_MEM_KERNEL_VIRT_START

Main kernel image mapping 시작

Kernel image

code · rodata · data · bss · noinit

K_MEM_VM_FREE_START

동적 mapping에 쓸 수 있는 낮은 경계

Unused · Available VM

새 mapping이 높은 주소 쪽 시작점에서 아래 방향으로 늘어남

Mapping stack

여러 mapped region과 각 guard page

K_MEM_VM_RESERVED

Demand paging 등 kernel 특수 용도 virtual page

K_MEM_VIRT_RAM_END

START + SIZE · virtual space 끝

  • K_MEM_VIRT_RAM_START: page-aligned virtual space 시작이며 현재 CONFIG_KERNEL_VM_BASE와 같습니다.
  • K_MEM_VIRT_RAM_SIZE: page-aligned virtual space 크기이며 현재 CONFIG_KERNEL_VM_SIZE와 같습니다.
  • K_MEM_VIRT_RAM_END: START + SIZE입니다.
  • K_MEM_KERNEL_VIRT_START: linker script의 z_mapped_start와 같으며 boot 때 kernel image 시작 virtual address입니다.
  • K_MEM_KERNEL_VIRT_END: linker script의 z_mapped_end와 같으며 kernel image 끝 virtual address입니다.
  • K_MEM_VM_FREE_START: memory mapping용 address를 할당할 수 있는 시작점으로 CONFIG_ARCH_MAPS_ALL_RAM에 따라 달라집니다.
  • K_MEM_VM_RESERVED: demand paging 등 kernel function을 지원하는 special-purpose virtual page 영역입니다.

CONFIG_ARCH_MAPS_ALL_RAM이 켜져 모든 physical memory가 virtual space에 mapping되면 K_MEM_VM_FREE_START는 CONFIG_SRAM_BASE_ADDRESS + CONFIG_SRAM_SIZE입니다. 꺼져 있으면 kernel image 끝인 K_MEM_KERNEL_VIRT_END와 같습니다.

Virtual memory mapping

Boot 때 mapping 구성

  • .text: read-only·executable이며 kernel과 user mode 모두 접근합니다.
  • .rodata: read-only·non-executable이며 두 mode 모두 접근합니다.
  • .data, .bss, .noinit 등: read-write·non-executable이며 kernel mode만 접근합니다.

User-mode thread stack은 thread 생성 때 해당 thread에 read-write access가 자동 부여됩니다. Global variable은 기본적으로 user thread가 접근할 수 없으며 Memory Domain과 Partition API로 global data를 공유해야 합니다.

이 mapping들의 cache mode는 architecture별로 none, write-back 또는 write-through일 수 있습니다. SoC는 boot에 필요한 device MMIO 같은 추가 mapping을 자체 SoC configuration에 정의합니다.

Anonymous memory mapping

사용하지 않은 physical memory는 필요할 때 virtual space에 mapping할 수 있습니다. Heap allocation과 개념적으로 비슷하지만 page-size alignment가 필요하고 access control이 더 세밀합니다.

  • k_mem_map() 요청 크기는 page size의 배수여야 합니다.
  • 반환 주소는 K_MEM_VM_FREE_START와 K_MEM_VIRT_RAM_END 사이입니다.
  • Mapped region이 physical memory에서 연속이라는 보장은 없습니다.
  • Buffer underrun·overrun 접근을 잡도록 virtual region 바로 앞뒤에 guard page를 자동 할당합니다.

k_mem_unmap()으로 mapping을 해제합니다. map과 unmap에 반드시 같은 region size를 넘겨야 합니다. Unmap 함수는 해제 전에 유효한 mapped region인지 검사하지 않습니다.

API 참고: kernel_memory_management

K_MEM_CACHE_NONE

Caching하지 않습니다. 대부분의 driver가 원하는 mode입니다.

K_MEM_CACHE_WT

Write-through caching입니다. 일부 driver에서 사용합니다.

K_MEM_CACHE_WB

완전한 write-back caching입니다. 일반 RAM mapping에 사용하는 mode입니다.

K_MEM_CACHE_MASK

k_map() flags 인수에서 cache mode용으로 예약된 bit mask입니다. Cache mode 값들은 상호 배타적입니다.

K_MEM_PERM_RW

Region에 read/write access를 주어 read-only가 아니게 합니다.

K_MEM_PERM_EXEC

보통 금지되는 executable permission을 region에 부여합니다.

K_MEM_PERM_USER

기본 supervisor-only인 region을 user mode에서도 접근 가능하게 합니다.

K_MEM_DIRECT_MAP

Virtual address와 physical address를 1:1로 mapping합니다.

K_MEM_MAP_UNINIT

Mapped region을 0으로 초기화한다고 보장하지 않습니다. 성능은 나아질 수 있지만 frame에 indeterminate data, zero 또는 sensitive information이 남아 있을 수 있습니다. 어떤 경우에도 안전하지 않으므로 K_MEM_PERM_USER와 함께 사용할 수 없습니다.

K_MEM_MAP_LOCK

Region을 memory에 pin해 page-out되지 않게 합니다. Mapping 호출이 반환된 뒤 page-out 또는 copy-on-write 때문에 page fault가 나지 않도록 필요한 physical frame을 미리 가져와 고정합니다.

size_t k_mem_free_get(void)

현재 free RAM page frame이 나타내는 가용 physical memory byte 수를 반환합니다. Demand paging이 켜져 있으면 이 값보다 더 할당할 수도 있고, concurrent mapping이나 page-in이 일어나면 결과는 즉시 낡을 수 있습니다.

반환값: Free physical RAM 크기(byte)입니다.

static inline void *k_mem_map(size_t size, uint32_t flags)

Anonymous physical memory를 Zephyr virtual address space에 mapping합니다. Kernel이 base virtual address를 고르고 flags에 따라 모든 context의 permission을 설정합니다. User thread별 access control이 필요하면 여기서 K_MEM_PERM_USER를 켜지 말고 mapping 뒤 memory-domain API로 관리해야 합니다. 이 flag를 직접 켜면 모든 user thread가 접근합니다. K_MEM_MAP_UNINIT이 없으면 memory를 0으로 채웁니다. Physical 연속성은 보장하지 않으며 연속 buffer는 build time에 정적으로 할당·pin해야 합니다. Mapping은 write-back cache를 사용하고 반환 주소와 size는 page-aligned입니다. 요청 앞뒤 guard page 두 장도 함께 예약하므로 총 virtual allocation은 요청 크기보다 두 page 큽니다.

매개변수

  • size: page-aligned mapping 크기
  • flags: K_MEM_PERM_* 및 K_MEM_MAP_* control flag

반환값: Mapped virtual address이며 virtual 공간, physical memory 또는 paging structure memory가 부족하면 NULL입니다.

static inline void k_mem_unmap(void *addr, size_t size)

Page-aligned region mapping을 제거합니다. 연결 page frame은 free되고 kernel이 virtual address 영역을 재사용할 수 있으며 paged-out data는 버립니다. 애초에 mapping되지 않은 영역에 호출하면 undefined behavior입니다.

매개변수

  • addr: page-aligned base virtual address
  • size: page-aligned region 크기
size_t k_mem_region_align(uintptr_t *aligned_addr, size_t *aligned_size, uintptr_t addr, size_t size, size_t align)

임의의 address region 전체를 덮으면서 base와 size가 지정 alignment에 맞는 확장 region을 계산합니다.

매개변수

  • aligned_addr: 정렬된 주소를 쓸 위치
  • aligned_size: 정렬된 region 크기를 쓸 위치
  • addr: 원래 region base
  • size: 원래 region 크기
  • align: 주소와 크기에 적용할 alignment

반환값: aligned_addr과 원래 addr 사이 offset입니다.

Source

출처

영어 원문에는 문단, 문서 지시문, 표, 코드, 코드 심벌, 경로를 그대로 보존했습니다.