Obsah
- Fyzická paměť
- Virtuální paměť (z pohledu kernelu)
- Způsoby alokace paměti
Detekce fyzické paměti
- platformově závislé
- i386: arch/i386/boot/setup.S
- ještě v reálném módu
- data na adresách 0x90000 - 0x901FF
- int 15h, AX=0xE820
- informace o paměťových regionech (ACPI memory map)
- čte se prvních 32 záznamů
- záznamy:
8B | base address |
8B | length |
4B | range type |
- 0x01 — available memory
- 0x02 — not available (ROM, HW mapped mem., etc.)
- 0x03 — ACPI memory
- 0x04 — ACPI NVS memory
|
- int 15h, AX=0xE801
- velikost paměti v jednotkách 1 KB (pro 0 - 16 MB), resp. 64 KB (> 16 MB)
- int 15h, AX=0x8800
- failback, 1 KB jednotky, max. 64 MB (někdy jen 16MB)
- parametr kernelu
Paměťové zóny
- rozdělení fyzické paměti
- význam zón platformově závislý
- i386
- arch/i386/m/init.c
- DMA (0 - 16 MB)
- Normal (0 - 896 MB)
- High (> 896 MB)
- paměť nemapovatelná 1:1 do virtuálního adresního prostoru kernelu
- používá se převážně pro user space stránky
- popis zóny (linux/mmzone.h)
typedef struct zone_strunct {
spinlock_t lock;
unsigned long free_pages;
unsigned long pages_min;
unsigned long pages_low;
unsigned long pages_high;
int need_balance;
free_area_t free_area[MAX_ORDER];
wait_queue_head_t *wait_table;
unsigned long wait_table_size;
unsigned long wait_table_shift;
struct pglist_data *zone_pgdat;
struct page *zone_mem_map;
unsigned long zone_start_paddr;
unsigned long zone_start_mapnr;
char *name;
unsigned long size;
} zone_t;
Adresní prostor
- virtuální adresní prostor z pohledu kernelu
- ploché mapování
- i386: 3/1 GB split
- 0 - 3 GB (0 - PAGE_OFFSET-1)
- user space mapping
- mapovaná paměť kernelu
- 3 - 4 GB (PAGE_OFFSET - 0xFFFFFFFF)
- 1:1 mapování fyzické paměti
- fyzicky kernel uložen od 2. MB paměti
Přístup k paměti
- segmentace (např. i386)
- nevyužita
- výchozí segmenty
0x10 | kernel code |
0x18 | kernel data/stack |
0x23 | user code |
0x2B | user space data/stack |
- kód odpovídá CS, data/stack odpovídají DS, SS (ES, ...)
- pokrývají celé 4 GB
- všechny segmenty v GDT
- LDT se přímo nepoužívají, sys_modify_ldt pro práci s nimi (Wine)
- dříve každý proces měl vlastní TSS
- stránkování
- interně: 3úrovňové
- page global directory
- page middle directory
- page table
- makra
- PAGE_SHIFT, PMD_SHIFT, PGDIR_SHIFT
- i386: 2úrovňové (10:10:12)
- page global directory jednopoložková
- PAE: 2:9:9:12
- popis stránky v poli mem_map[MAP_NR]
typedef struct page {
struct page *next;
struct page *prev;
struct inode *inode;
unsigned long offset;
struct page *next_hash;
atomoic_t count;
unsigned long flags;
struct wait_queue *wait;
struct page **prev_hash;
struct buffer_head *buffers;
} mem_map_t;
Buddy system
- alokátor paměti s granularitou stránek
- udržuje seznamy volných stránek velikosti odpovídajících jednotlivým řádům (počet stránek je 2order)
- pole typu free_area_struct
- bitmapy použitých bloků
- zvlášť seznamy pro zóny DMA, Normal, High
- stránky jsou souvislé ve fyzické paměti
- vrací virtuální adresu
- pro převod makra __pa(), __va()
- alokace (mm/page_alloc.c)
- get_zeroed_page(gfp_mask)
- __get_free_page(gfp_mask)
- __get_free_pages(gfp_mask, order)
- velikost v log2 počtu stránek, limit typicky 2 MB
- flagy
- GFP_KERNEL
- v kontextu procesu, může blokovat
- GFP_ATOMIC
- v kontextu přerušení, neblokuje
- GFP_BUFFER
- pro bufferovou cache, může blokovat, neprovádí flush dirty stranek cache
- GFP_USER
- v kontextu procesu, může blokovat, low-priority
- GFP_HIGHUSER
- jako GFP_USER, ze zóny High
- __GFP_DMA
- modifikátor pro zónu DMA (dříve __get_dma_pages())
- __GFP_HIGHMEM
- modifikátor pro zónu High
- __GFP_IO
- modifikátor povolující odswapovat, povoluje blokování
- dealokace
- free_page(addr)
- free_pages(addr, order)
Slab allocator
- alokace paměťových oblastí předem daných vlastností (mm/slab.c)
- délka
- konstruktor, destruktor
- cacheování již alokovaných objektů
- objekty stejného typu se seskupují do cachí
- cache jsou pojmenovány, viz /proc/slabinfo
- cache odkazuje na slab
- jedna nebo více stránek (spojitých) obsahující alokované a volné objekty
- kmem_cache_t
- kmem_slab_t
- pro objekty menší než 512 B uložen na konci slabu
- stránky s objekty se dealokují jen explicitně
- druhy cachí
- general
- pro potřeby alokátoru (cache_cache, cache_slabp, cache_sizes)
- specific
- kmem_cache_create(name, size, offset, flags, ctor, dtor)
- vytvoření nové specifické cache, bez slabů
- SLAB_NOREAP, SLAB_HWCACHE_ALIGN, SLAB_CACHE_DMA
- kmem_cache_alloc(*cachep, flags)
- alokace nového objektu ve slabu
- SLAB_NOIO, SLAB_ATOMIC, SLAB_DMA
- kmem_cache_free()
kmalloc()
- alokace fyzicky souvislé paměti (mm/slab.c)
- využívá slab allocator
- bloky velikosti mocniny dvojky, obvykle od 32 B do 128 KB
- size-32, size-32(DMA), ...
- flagy shodné jako pro get_free_page()
- paměť není inicializovaná
- dealokace
vmalloc()
- alokace mapované paměti (mm/vmalloc.c)
- fyzicky nesouvislá, souvislá ve virtuální paměti
- jednotlivé stránky pomocí __get_free_page()
- nelze použít v kontextu přerušení (GFP_KERNEL)
- granularita je po stránkách
- efektivní jen pro více než jednu stránku
- velikost omezena fyzickou pamětí
- dealokace
Alokace během bootu
- alokace velkého bloku fyzicky souvislé paměti
- trik s mem=
- reserve_bootmem(addr, size)
- označí část paměti jako reserved
- alloc_bootmem(size)
- alokace libovolné nezarovnané oblasti
- alloc_bootmem_pages(size)
- alokace oblasti zarovnané na stránky
Alokace paměti pro user space
- mapování specifické procesu
- popsáno regiony virtuální paměti
- bázová adresa, délka, přístupová práva
- code, init data, data, stack, shared code, shared data, stack
- nepřekrývající
- slučování přilehlých (se stejnými právy)
- kernel udržuje ve spojovém seznamu nebo AVL stromu (pro více než AVL_MIN_MAP_COUNT, typicky 32)
- klasický POSIXový syscall brk se převádí na mremap a munmap regionu haldy
- demand paging
- copy-on-write
Odkazy
- Bovet, Cesati: Understanding the Linux Kernel (O'Reilly)
- Nayani, Gorman, de Castro: Memory Management in Linux (LKDP)
- Gorman: Understanding The Linux Virtual Memory Manager (LKDP)
- Gorman: Code Commentary On The Linux Virtual Memory Manager (LKDP)