• ARM平台linux内核Notes 1


    linux内存管理

      嵌入式处理器的分页管理为二级映射,内存空间与I/O空间统一编址,而x86处理器采用三级映射,内存空间与I/O空间独立编址。

     

      在32位嵌入式系统中,存储空间的地址范围从0x0000_0000到0xFFFF_FFFF,内存和I/O共享从这4GB地址空间范围。

      其主要包含以下几种存储空间:

      1)设备空间(MT_DEVICE):二级分页

      2)内部高速SRAM空间(MT_CACHECLEAN):一级分段

      3)内部mini cache空间(MT_MINICLEAN):一级分段

      4)低端中断向量(MT_LOW_VECTORS):两级分页

      5)高端中断向量(MT_HIGH_VECTORS):两级分页

      6)RAM内存空间(NT_MEMORY):一级分段

      7)ROM(flash)空间(MT_ROM):一级分段

     

    --------------------------------------------- S3C6410 datasheet -----------------------------------------------------

       S3C6410 支持32 位物理地址域,并且这些地址域分成两部分,一部分用于存储,另一部分用于外设。

       通过SPINE 总线访问主存,主存的地址范围是0x0000_0000~0x6FFF_FFFF。主存部分分成四个区域:

    引导镜像区、内部存储区、静态存储区和动态存储区。

      引导镜像区的地址范围是从0x0000_0000~0x07FF_FFFF,但是没有实际的映射内存

      每块内部存储器的起始地址是确定的。

      内部ROM 的地址范围是0x0800_0000~0x0BFF_FFFF,但是实际存储仅32KB。该区域是只读的,并且当内部ROM 启动被选择时,该区域能映射到引导镜像区。

      内部SRAM 的地址范围是0x0C00_0000~0x0FFF_FFFF,但是实际存储仅4KB。该区域能被读和写,当NAND 闪存启动被选择时能映射到引导镜像区。

      静态存储区的地址范围是0x1000_0000~0x3FFF_FFFF。通过该地址区域能访问SROM、SRAM、 NOR Flash、同步NOR接口设备、和Steppingstone。

      动态存储区的地址范围是0x4000_0000~0x6FFF_FFFF。DMC0有权使用地址0x4000_0000~0x4FFF_FFFF,并且DMC1有权使用地址0x5000_0000~0x6FFF_FFFF。

      外设区域通过PERI 总线被访问,它的地址范围是0x7000_0000~0x7FFF_FFFF。这个地址范围的所有的SFR 能被访问。而且如果数据需要从NFCON 或CFCON 传输,这些数据需要通过PERI 总线传输。

    --------------------------------------------- 我是分割线 -------------------------------------------------------------

    内存页(page)

      ARM处理器支持1KB-4KB的页框大小。

      ARM处理器默认页框打下为4KB。

      页内存的结构为 struct page:

      

    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
    };
    
    /*
     * A region containing a mapping of a non-memory backed file under NOMMU
     * conditions.  These are held in a global tree and are pinned by the VMAs that
     * map parts of them.
     */
    struct vm_region {
            struct rb_node  vm_rb;          /* link in global region tree */
            unsigned long   vm_flags;       /* VMA vm_flags */
            unsigned long   vm_start;       /* start address of region */
            unsigned long   vm_end;         /* region initialised to here */
            unsigned long   vm_top;         /* region allocated to here */
            unsigned long   vm_pgoff;       /* the offset in vm_file corresponding to vm_start */
            struct file     *vm_file;       /* the backing file or NULL */
    
            int             vm_usage;       /* region usage count (access under nommu_region_sem) */
            bool            vm_icache_flushed : 1; /* true if the icache has been flushed for
                                                    * this region */
    };

     

    内存区段(bank)

      一个内存bank表示一块连续内存区域,,一个bank一般对应处理器的一个RAM片选管脚(pin)上链接的RAM芯片内存空间。

      现代处理器通常至少有4个RAM片选管脚,每个管脚所连RAM芯片在系统总的起始地址和大小可以通过寄存器设置。

      对应内存bank的数据结构有struct meminfo:

    struct meminfo {
            int nr_banks;
            struct membank bank[NR_BANKS];
    };

    内存节点(node)

      内存节点是指由一个或者多个内存bank组成的内存集合,如果一个内存节点由多个内存bank组成,这些内存bank之间可以连续也可以不连续,即节点内可以存在内存孔洞。

      在设置中

    CONFIG_DISCONTIGMEM
    /*
    未设置,则只有一个bank,即只有一个内存node,内存地址连续;
    处理器地址寻址间每两个RAM的地址范围固定,若接入的RAM小于这个最大寻址范围,将出现内存孔洞。此时,若不设置CONFIG_DISCONTIGMEM,所有内存bank都属于内存节点0,如果设置了CONFIG_DISCONTIGMEM,将浪费一定的时间为孔洞内存创建struct page。
    孔洞对系统启动后无影响,因为孔洞已经被mem_init()回收。
    */

      对应内存节点的重要数据结构有 struct pglist_data(pg_data_t):

    typedef struct pglist_data {
            struct zone node_zones[MAX_NR_ZONES];
            struct zonelist node_zonelists[MAX_ZONELISTS];
            int nr_zones;
    #ifdef CONFIG_FLAT_NODE_MEM_MAP /* means !SPARSEMEM */
            struct page *node_mem_map;
    #ifdef CONFIG_CGROUP_MEM_RES_CTLR
            struct page_cgroup *node_page_cgroup;
    #endif
    #endif
    #ifndef CONFIG_NO_BOOTMEM
            struct bootmem_data *bdata;
    #endif
    #ifdef CONFIG_MEMORY_HOTPLUG
            /*
             * Must be held any time you expect node_start_pfn, node_present_pages
             * or node_spanned_pages stay constant.  Holding this will also
             * guarantee that any pfn_valid() stays that way.
             *
             * Nests above zone->lock and zone->size_seqlock.
             */
            spinlock_t node_size_lock;
    #endif
            unsigned long node_start_pfn;
            unsigned long node_present_pages; /* total number of physical pages */
            unsigned long node_spanned_pages; /* total size of physical page
                                                 range, including holes */
            int node_id;
            wait_queue_head_t kswapd_wait;
            struct task_struct *kswapd;
            int kswapd_max_order;
    } pg_data_t;

    内存页区(zone)

      内存页区是定义在内存节点(node)中的概念,每个内存节点可以分成3个内存页区,即

      1、DMA页区(ZONE_DMA=0):可DMA操作

      2、Normal页区(ZONE_NORMAL=1):禁止DMA操作

      3、HighMem页区(ZONE_HIGHMEM=2):高端内存区域

      对应内存页区的重要数据结构有struct zone(内容比较长,就不粘贴了~、~,上LXR自己找找呗)

    空闲内存区域(free area)

      空闲内存区域是内存页区内连续2^N页空闲内存组成的内存区域,其中N的范围在0~MAX_ORDER-1之间的整数,MAX_ORDER默认为11.

      对应的数据结构有struct free_area:

    struct free_area {
            struct list_head        free_list[MIGRATE_TYPES];
            unsigned long           nr_free;
    };

     

  • 相关阅读:
    WCF 第十二章 对等网 实现一个自定义对等网解析器
    WCF 第十二章 对等网 System.Net.PeerToPeer.Collaboration
    WCF 第十二章 对等网 使用Windows Vista 来进行合作
    WCF 第十二章 对等网 使用PNRP解决对等网络问题
    WCF 第十二章 对等网 点对点应用程序
    WCF 第十二章 对等网 限制一条消息的跳数
    WCF 第十二章 对等网 创建P2P应用程序
    C#解析HTML
    C#中的DLL注入
    VC简单实现淡入淡出效果
  • 原文地址:https://www.cnblogs.com/plinx/p/2860228.html
Copyright © 2020-2023  润新知