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 o ještě v reálném módu o data na adresách 0x90000 - 0x901FF + int 15h, AX=0xE820 o informace o paměťových regionech (ACPI memory map) # čte se prvních 32 záznamů o 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 o velikost paměti v jednotkách 1 KB (pro 0 - 16 MB), resp. 64 KB (> 16 MB) + int 15h, AX=0x8800 o failback, 1 KB jednotky, max. 64 MB (někdy jen 16MB) + parametr kernelu o mem=128m Paměťové zóny * rozdělení fyzické paměti + význam zón platformově závislý + i386 o arch/i386/m/init.c # DMA (0 - 16 MB) @ ISA DMA přenosy # Normal (0 - 896 MB) @ běžná paměť # 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 o 0 - 3 GB (0 - PAGE_OFFSET-1) # user space mapping # mapovaná paměť kernelu @ vmalloc() o 3 - 4 GB (PAGE_OFFSET - 0xFFFFFFFF) # 1:1 mapování fyzické paměti @ kmalloc() # 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 o kód odpovídá CS, data/stack odpovídají DS, SS (ES, ...) o pokrývají celé 4 GB + všechny segmenty v GDT o LDT se přímo nepoužívají, sys_modify_ldt pro práci s nimi (Wine) o dříve každý proces měl vlastní TSS * stránkování + interně: 3úrovňové o page global directory o page middle directory o page table + makra o PAGE_SHIFT, PMD_SHIFT, PGDIR_SHIFT + i386: 2úrovňové (10:10:12) o page global directory jednopoložková o 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 2^order) o pole typu free_area_struct o 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 o pro převod makra __pa(), __va() + alokace (mm/page_alloc.c) o get_zeroed_page(gfp_mask) o __get_free_page(gfp_mask) o __get_free_pages(gfp_mask, order) # velikost v log[2] 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 o free_page(addr) o free_pages(addr, order) # hodnoty se nekontrolují Slab allocator * alokace paměťových oblastí předem daných vlastností (mm/slab.c) + délka + konstruktor, destruktor o v kernelu se nepoužívají + 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 o jedna nebo více stránek (spojitých) obsahující alokované a volné objekty + kmem_cache_t + kmem_slab_t o pro objekty menší než 512 B uložen na konci slabu + stránky s objekty se dealokují jen explicitně o při nedostatku paměti * druhy cachí + general o pro potřeby alokátoru (cache_cache, cache_slabp, cache_sizes) + specific o kmem_cache_create(name, size, offset, flags, ctor, dtor) # vytvoření nové specifické cache, bez slabů # SLAB_NOREAP, SLAB_HWCACHE_ALIGN, SLAB_CACHE_DMA o kmem_cache_alloc(*cachep, flags) # alokace nového objektu ve slabu # SLAB_NOIO, SLAB_ATOMIC, SLAB_DMA o kmem_cache_free() kmalloc() * alokace fyzicky souvislé paměti (mm/slab.c) + využívá slab allocator o 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 o kfree() vmalloc() * alokace mapované paměti (mm/vmalloc.c) + fyzicky nesouvislá, souvislá ve virtuální paměti + jednotlivé stránky pomocí __get_free_page() o nelze použít v kontextu přerušení (GFP_KERNEL) o granularita je po stránkách # efektivní jen pro více než jednu stránku + velikost omezena fyzickou pamětí + dealokace o vfree() Alokace během bootu * alokace velkého bloku fyzicky souvislé paměti + trik s mem= + reserve_bootmem(addr, size) o označí část paměti jako reserved + alloc_bootmem(size) o alokace libovolné nezarovnané oblasti + alloc_bootmem_pages(size) o alokace oblasti zarovnané na stránky Alokace paměti pro user space * mapování specifické procesu + popsáno regiony virtuální paměti o bázová adresa, délka, přístupová práva o 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) o klasický POSIXový syscall brk se převádí na mremap a munmap regionu haldy + demand paging + copy-on-write Odkazy 1. Bovet, Cesati: Understanding the Linux Kernel (O'Reilly) 2. Nayani, Gorman, de Castro: Memory Management in Linux (LKDP) 3. Gorman: Understanding The Linux Virtual Memory Manager (LKDP) 4. Gorman: Code Commentary On The Linux Virtual Memory Manager (LKDP) -- 1. http://www.oreilly.com/catalog/linuxkernel/ 2. http://puggy.symonds.net/~abhi/files/mm/ 3. http://www.csn.ul.ie/~mel/projects/vm/guide/html/understand/ 4. http://www.csn.ul.ie/~mel/projects/vm/guide/html/code/