x86下 线性地址到物理地址映射图示

来源:互联网 发布:怎么卸载顽固软件 编辑:程序博客网 时间:2024/05/22 03:23
可能有错,更新中。。。
x86下的linux


粗线表示此范围的物理内存此范围的线性空间是一一映射的
细线表示此范围的物理页框可以映射到此范围的线性空间

1.进程线性地址空间:用户进程的页面优先从ZONE_HIGTMEM分配,但也可以从其他


2.直接映射区:最大896MB,动态映射区最小120MB
有下面几个用于获取页框并返回一个位于直接映射区的线性地址的函数(④返回page指针)

void *kmalloc(size_t size, int flags);
kmalloc从从slab通用缓冲区获得已分配之内存,不管申请多少,每次实际获取到的字节数取整为32,64,128...所以会产生细小碎片
在ZONE_HIGHMEM存在的情况下,kmalloc若指定_ _GFP_HIGHMEM则可以获取ZONE_HIGHMEM的块(slab应该在ZONE_HIGHMEM页建立了通用缓存区吧)

定制slab后备缓存的小块内存:
先整页申请几页页框并每页平分成若干块储备起来
kmem_cache_t *kmem_cache_create(const char *name, size_t size,
                                size_t offset,
                                unsigned long flags,
                                void (*constructor)(void *, kmem_cache_t *,
                                                    unsigned long flags),
                                void (*destructor)(void *, kmem_cache_t *,
                                                   unsigned long flags));
说明:flags可取如下选项等,摘自slab.c,可见貌似不能获取ZONE_NORMAL页框
#define SLAB_DEBUG_FREE        0x00000100UL    /* DEBUG: Perform (expensive) checks on free */
#define SLAB_RED_ZONE        0x00000400UL    /* DEBUG: Red zone objs in a cache */
#define SLAB_POISON        0x00000800UL    /* DEBUG: Poison objects */
#define SLAB_HWCACHE_ALIGN    0x00002000UL    /* Align objs on cache lines */
#define SLAB_CACHE_DMA        0x00004000UL    /* Use GFP_DMA memory */
#define SLAB_STORE_USER        0x00010000UL    /* DEBUG: Store the last owner for bug hunting */
#define SLAB_PANIC        0x00040000UL    /* Panic if kmem_cache_create() fails */
。。。
在从上面储备块中申请一个空闲的块
void *kmem_cache_alloc(kmem_cache_t *cache, int flags);


获取整页,返回直接映射区的线性地址
get_zeroed_page(unsigned int flags);
Returns a pointer to a new page and fills the page with zeros.
_ _get_free_page(unsigned int flags);
Similar to get_zeroed_page, but doesn't clear the page.
_ _get_free_pages(unsigned int flags, unsigned int order);
Allocates and returns a pointer to the first byte of a memory area that is potentially several (physically contiguous) pages long but doesn't zero the area.
这些函数通常去获取ZONE_NORMAL的页框,但在ZONE_HIGHMEM存在的情况下,通过指定_ _GFP_HIGHMEM可以获取ZONE_HIGHMEM的页框

也可用以下函数获取整页,通上面一样也可指定_ _GFP_HIGHMEM,但返回的时page指针
struct page *alloc_pages_node(int nid, unsigned int flags,unsigned int order);
This function also has two variants (which are simply macros);
these are the versions that you will most likely use:
struct page *alloc_pages(unsigned int flags, unsigned int order);
struct page *alloc_page(unsigned int flags);
正是因为返回的page指针,此时可得知物理页框的地址,所以可以用于实现vmalloc,


3.动态映射区:

vmalloc函数可从所有物理内存区(即包括低端内存区高端内存区)获得页框,比如其申请16KB内存,其内部是调用alloc_page一个一个页的在适当内存区申请4个空闲页框,所以4个页框物理上未必是连续
然后将申请到的页框首地址用函数map_vm_area()填入4个连续的属于vmalloc的页表项,所以对应的线性地址肯定连续
由于属于vmalloc的页目录项在内核页目录中从992开始(但如果物理内存不足896MB则vmalloc对应的页目录项可以延伸到992内),所以4个页框对应的线性地址为均在3GB+896之上

直接用

alloc_page系函数,然后手动修改内核页表:将物理页框的首地址塞进自己喜欢的一个页表项中

4永久映射区:

Permanent Mappings
To map a given page structure into the kernel's address space, use
void *kmap(struct page *page)
This function works on either high or low memory. If the page structure belongs to a page in low memory, the page's virtual address is simply returned. If the page resides in high memory, a permanent mapping is created and the address is returned. The function may sleep, so kmap() works only in process context.
refer to lkd2 ch11 高端内存的映射一节

直接用
alloc_page系函数,

5.固定映射区:(lkd2中的临时映射区应该 part of 固定映射区)
见 ulk3 ch2固定映射的线性地址一节

看一下linux对所有物理页框的管理,每个物理页框对应一个page结构体
Chapter 11. Memory Management   lkd2

Pages
The kernel treats physical pages as the basic unit of memory management. Although the processor's smallest addressable unit is usually a word (or even a byte), the memory management unit (MMU, the hardware that manages memory and performs virtual to physical address translations) typically deals in pages. Therefore, the MMU manages the system's page tables with page-sized granularity (hence their name). In terms of virtual memory, pages are the smallest unit that matters.

As you'll see in Chapter 19, "Portability," each architecture enforces its own page size. Many architectures even support multiple page sizes. Most 32-bit architectures have 4KB pages, whereas most 64-bit architectures have 8KB pages. This implies that on a machine with 4KB pages and 1GB of physical memory, physical memory is divided up into 262,144 distinct pages.

The kernel represents every physical page on the system with a struct page structure. This structure is defined in <linux/mm.h>:

struct page {
        page_flags_t          flags;
        atomic_t              _count;
        atomic_t              _mapcount;
        unsigned long         private;
        struct address_space  *mapping;
        pgoff_t               index;
        struct list_head      lru;
        void                  *virtual;
};

Let's look at the important fields. The flags field stores the status of the page. Such flags include whether the page is dirty or whether it is locked in memory. Bit flags represent the various values, so at least 32 different flags are simultaneously available. The flag values are defined in <linux/page-flags.h>.

The _count field stores the usage count of the pagethat is, how many references there are to this page. When this count reaches negative zero, no one is using the page, and it becomes available for use in a new allocation. Kernel code should not check this field directly but instead use the function page_count(), which takes a page structure as its sole parameter. Although internally _count is negative one when the page is free, page_count() returns zero to indicate free and a positive nonzero integer when the page is in use. A page may be used by the page cache (in which case the mapping field points to the address_space object that is associated with this page), as private data (pointed at by private), or as a mapping in a process's page table.

The virtual field is the page's virtual address.
Normally, this is simply the address of the page in virtual memory. Some memory (called high memory) is not permanently mapped in the kernel's address space. In that case, this field is NULL and the page must be dynamically mapped when needed. We'll discuss high memory shortly.

The important point to understand is that the page structure is associated with physical pages, not virtual pages. Therefore, what the structure describes is transient at best. Even if the data contained in the page continues to exist, it might not always be associated with the same page structure because of swapping and so on. The kernel uses this data structure to describe whatever is stored in the associated physical page at that moment. The data structure's goal is to describe physical memory, not the data contained therein.

The kernel uses this structure to keep track of all the pages in the system, because the kernel needs to know whether a page is free (that is, if the page is not allocated). If a page is not free, the kernel needs to know who owns the page. Possible owners include user-space processes, dynamically allocated kernel data, static kernel code, the page cache, and so on.

Developers are often surprised that an instance of this structure is allocated for each physical page in the system. They think, "What a lot of memory used!" Let's look at just how bad (or good) the space consumption is from all these pages.Assume struct page consumes 40 bytes of memory, the system has 4KB physical pages, and the system has 128MB of physical memory. In that case, all the page structures in the system consume slightly more than 1MB ofmemorynot too high a cost for managing all of the sys tem's physical pages.


2012-12-19 21:10:11 找到一个网址,暂时记下
http://blog.csdn.net/bullbat/article/details/7304404#comments