DSP

再读uclinux-2008r1(bf561)内核存储区域管理(1):相关数据结构

2019-07-13 17:03发布

  快乐虾 http://blog.csdn.net/lights_joy/ lights@hb165.com    本文适用于 ADI bf561 DSP 优视BF561EVB开发板 uclinux-2008r1-rc8 (移植到vdsp5) Visual DSP++ 5.0    欢迎转载,但请保留作者信息   Linux支持非一致内存访问(Non-Uniform Memory Access, NUMA)模型,在这种模型中,给定CPU对不同内存单元的访问时间可能不一样。系统的物理内存被划分为几个节点。在一个单独的节点内,任一给定CPU访问页面所需的时间都是相同的。但是对不同的CPU,这个时间可能就不同。对每个CPU而言,内核都试图把耗时节点的访问次数减到最少,这就需要小心地选择CPU最常引用的内核数据结构的存放位置。每个节点中的物理内存又可以分为几个管理区(zone) x86的体系结构下,Linux将内存分为3个管理区: ZONE_DMA:包含低于16M的内存页,因为ISA总线的DMA处理器有严格限制,只能对RAM的前16M进行寻址。 ZONE_NORMAL:包含高于16M且低于896M的内存。 ZONE_HIGHMEM:包含高于896M的内存。 对于BF561而言,DMA将可以访问整个内存区域,当然,由于anomaly-05000263的缘故,在启用ICACHE的情况下,可用内存将限制为60M。所以在内核中,实际只使用了一个内存区,ZONE_DMA,在这个内存区中,包含了所有的内存范围。 下面试图通过对存储区域的初始化来分析下内核的数据表示。

1.1.1   相关数据结构

1.1.1.1             page

内核的存储管理是以page为单位的,每个page的大小为4K,且每个page都用一个page结构体来进行描述,这些page的描述做为一个数组放在内核代码之后。因而这里就涉及到3个量:一个是4K的实际页面的地址,即物理地址,在内核中表示为Virtual Address;另一个为描述此页面的page结构指针,用page表示;还有一个是这个page结构体在整个page数组中的序号,内核称之为pfn。这三个地址之间可以用6个宏来进行相互转换。 page结构体的定义在include/linux/mm_types.h中: /*  * Each physical page in the system has a struct page associated with  * it to keep track of whatever it is we are using the page for at the  * moment. Note that we have no way to track which tasks are using  * a page, though if it is a pagecache page, rmap structures can tell us  * who is mapping it.  */ 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 uses */               short unsigned int inuse;               short unsigned int offset;          };      };      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.                              */          };          spinlock_t ptl;          struct {           /* SLUB uses */          void **lockless_freelist;          struct kmem_cache *slab;    /* Pointer to slab */          };          struct {          struct page *first_page;    /* Compound 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 !                         */ }; l         lru 这个结构体根据这个页面应用的不同有不同的含义,当此页面空闲时或者此页面用于高速缓存时,这个结构体用于将页面链接起来的双链表。而当此页面用于SLAB算法时,它的next指针将指向这个slab所在的cache,即一个kmem_cache的结构体。而其prev指针将指向这个slab。这两个指针都是通过slab_map_pages函数进行设置的。 l         flags 这个结构体中的flags成员每个位的定义在include/linux/page_flags.h中: /*  * Various page->flags bits:  *  * PG_reserved is set for special pages, which can never be swapped out. Some  * of them might not even exist (eg empty_bad_page)...  *  * The PG_private bitflag is set on pagecache pages if they contain filesystem  * specific data (which is normally at page->private). It can be used by  * private allocations for its own usage.  *  * During initiation of disk I/O, PG_locked is set. This bit is set before I/O  * and cleared when writeback _starts_ or when read _completes_. PG_writeback  * is set before writeback starts and cleared when it finishes.  *  * PG_locked also pins a page in pagecache, and blocks truncation of the file  * while it is held.  *  * page_waitqueue(page) is a wait queue of all tasks waiting for the page  * to become unlocked.  *  * PG_uptodate tells whether the page's contents is valid.  When a read  * completes, the page becomes uptodate, unless a disk I/O error happened.  *  * PG_referenced, PG_reclaim are used for page reclaim for anonymous and  * file-backed pagecache (see mm/vmscan.c).  *  * PG_error is set to indicate that an I/O error occurred on this page.  *  * PG_arch_1 is an architecture specific page state bit.  The generic code  * guarantees that this bit is cleared for a page when it first is entered into  * the page cache.  *  * PG_highmem pages are not permanently mapped into the kernel virtual address  * space, they need to be kmapped separately for doing IO on the pages.  The  * struct page (these bits with information) are always mapped into kernel  * address space...  *  * PG_buddy is set to indicate that the page is free and in the buddy system  * (see mm/page_alloc.c).  *  */   /*  * Don't use the *_dontuse flags.  Use the macros.  Otherwise you'll break  * locked- and dirty-page accounting.  *  * The page flags field is split into two parts, the main flags area  * which extends from the low bits upwards, and the fields area which  * extends from the high bits downwards.  *  *  | FIELD | ... | FLAGS |  *  N-1     ^             0  *          (N-FLAGS_RESERVED)  *  * The fields area is reserved for fields mapping zone, node and SPARSEMEM  * section.  The boundry between these two areas is defined by  * FLAGS_RESERVED which defines the width of the fields section  * (see linux/mmzone.h).  New flags must _not_ overlap with this area.  */ #define PG_locked       0   /* Page is locked. Don't touch. */ #define PG_error       1 #define PG_referenced       2 #define PG_uptodate         3   #define PG_dirty        4 #define PG_lru              5 #define PG_active      6 #define PG_slab             7   /* slab debug (Suparna wants this) */   #define PG_owner_priv_1     8   /* Owner use. If pagecache, fs may use*/ #define PG_arch_1      9 #define PG_reserved         10 #define PG_private     11   /* If pagecache, has fs-private data */   #define PG_writeback        12   /* Page is under writeback */ #define PG_compound         14   /* Part of a compound page */ #define PG_swapcache        15   /* Swap page: swp_entry_t in private */   #define PG_mappedtodisk     16   /* Has blocks allocated on-disk */ #define PG_reclaim     17   /* To be reclaimed asap */ #define PG_buddy       19   /* Page is free, on buddy lists */   /* PG_owner_priv_1 users should have descriptive aliases */ #define PG_che