Linux板级内存管理之-内核的页,页框,页帧
osboy - mcuos.com站长原创
mcuos.com@gmail.com
Linux的页描述符page管理的物理内存,他把物理内存划分为4kbyte大小的页框,用页描述符记录这些页框的状态,并统一放到structpage *mem_map数组中。
下面我们来看一张图:
如果我们知道物理内存的基地址,可以通过上面的图看出,每个页的物理基地址是可知的,这张图也说明了页,页框,页帧之间的关系。
一个物理抽象的“页”有4kbytes的大小,一个4kbytes的页组成图中的框,我们称之为“页框”,而“页帧”则是从0开始数给每个页框用整数编号,以此每个页框的号码为“页帧”号。
从图中可以看出“页帧”左移12位,就是对用“页框”的物理基地址。反之亦然。
那么把这些个概念,用数据结构怎么表示呢?下面我们看看:
对“页”的数据结构表述:
- struct page {
- unsigned long flags; /* Atomic flags, some possibly
- * updated asynchronously */
- atomic_t _count; /* Usage count, see below. */
- union {
- atomic_t _mapcount; /* Count of ptes mapped in mms,
- * to show when page is mapped
- * & limit reverse map searches.
- */
- struct { /* SLUB */
- u16 inuse;
- u16 objects;
- };
- };
- union {
- struct {
- unsigned long private; /* Mapping-private opaque data:
- * usually used for buffer_heads
- * if PagePrivate set; used for
- * swp_entry_t if PageSwapCache;
- * indicates order in the buddy
- * system if PG_buddy is set.
- */
- struct address_space *mapping; /* If low bit clear, points to
- * inode address_space, or NULL.
- * If page mapped as anonymous
- * memory, low bit is set, and
- * it points to anon_vma object:
- * see PAGE_MAPPING_ANON below.
- */
- };
- #if USE_SPLIT_PTLOCKS
- spinlock_t ptl;
- #endif
- struct kmem_cache *slab; /* SLUB: Pointer to slab */
- struct page *first_page; /* Compound tail pages */
- };
- union {
- pgoff_t index; /* Our offset within mapping. */
- void *freelist; /* SLUB: freelist req. slab lock */
- };
- struct list_head lru; /* Pageout list, eg. active_list
- * protected by zone->lru_lock !
- */
- /*
- * On machines where all RAM is mapped into kernel address space,
- * we can simply calculate the virtual address. On machines with
- * highmem some memory is mapped into kernel virtual memory
- * dynamically, so we need a place to store that address.
- * Note that this field could be 16 bits on x86 ... ;)
- *
- * Architectures with slow multiplication can define
- * WANT_PAGE_VIRTUAL in asm/page.h
- */
- #if defined(WANT_PAGE_VIRTUAL)
- void *virtual; /* Kernel virtual address (NULL if
- not kmapped, ie. highmem) */
- #endif /* WANT_PAGE_VIRTUAL */
- #ifdef CONFIG_WANT_PAGE_DEBUG_FLAGS
- unsigned long debug_flags; /* Use atomic bitops on this */
- #endif
- #ifdef CONFIG_KMEMCHECK
- /*
- * kmemcheck wants to track the status of each byte in a page; this
- * is a pointer to such a status block. NULL if not tracked.
- */
- void *shadow;
- #endif
- };
复制代码
内核把内存分成不同的页,而每个页都有个page变量与其相对应,所有的page变量的物理地址组合起来通过一个数组:
来表示。可以从上图中看出。
在linux内核中有定义这些变量的转化宏:
在arch/arm/mach-xxx/include/mach/memory.h中有, #define PHYS_OFFSET
UL(0x00000000) 在arch/arm/include/asm/memory.h中有: #define PHYS_PFN_OFFSET
(PHYS_OFFSET >> PAGE_SHIFT) #define PAGE_SHIFT
12 #define ARCH_PFN_OFFSET
PHYS_PFN_OFFSET 在Include/asm-generic/memory-model.h中有: #if defined(CONFIG_FLATMEM) #define __pfn_to_page(pfn)
(mem_map + ((pfn) - ARCH_PFN_OFFSET)) #define __page_to_pfn(page)
((unsignedlong)((page) - mem_map) + \
ARCH_PFN_OFFSET)
#define page_to_pfn __page_to_pfn #define pfn_to_page __pfn_to_page
明白了上面我分析的,那么对这些转换宏定义就一目了然了吧。 |