您的位置:首页 > 运维架构 > Linux

ARM—Linux基本数据类型综合应用实例

2011-04-06 22:37 579 查看
本文章将带读者走进Linux内核,亲身感受一下这个优秀的操作系统Linux的具体搭建过程。其实读者可以看到,若将这一高楼大厦分解细分为砖瓦,那么每一部分其实也并不是那么难的。

在Linux内核中,直接使用基本数据类型来构建的关键数据结构微乎其微,一般都是将基本数据类型组合起来,构成构造数据类型(如结构体等),来组成其关键的数据结构。

本文就以Linux中内存管理中的物理页为例进行讲解。

1、内存页管理机制

内存把物理页作为内存管理的基本单位。尽管处理器的最小可寻址单位通常为字,但是,内存管理单元(MMU,管理内存并把虚拟地址转换为物理地址的硬件)通常是以页为单位进行处理的。也正因为如此,MMU以页的大小为单位来管理系统中的页表。因此,从虚拟内存的角度来看,页就是最小分配单位。

不同的体系结构,所支持的页大小也不尽相同,读者可以查看/include/asm../page.h中的定义,如下所示:

/*include/asm-i386/page.h*/

/*PAGE_SHIFT决定页大小,页大小为4KB*/

#define PAGE_SHIFT 12

/*include/asm-alpha/page.h*/

/*页大小为8KB*/

#define PAGE_SHIFT 13

/*include/asm-arm/page.h*/

/*页大小为4KB*/

#define PAGE_SHIFT 12

/*include/asm-arm26/page.h,arm2600*/

/*若定义了页大小为16KB*/

#if defined(CONFIG_PAGESIZE_16)

#define PAGE_SHIFT 14 /*16KB*/

/*其他情况页大小为32KB*/

#else /*default*/

#define PAGE_SHIFT 15 /*32KB*/

#endif

/*include/asm-ppc/page.h*/

/*页大小为4KB*/

#define PAGE_SHIFT 12

这里的PAGE_SHIFT是用于决定页大小的,将它的数值进行以2为底取幂运算,所得到的结果就是页得大小,比如2的12次方为4K。可以看到,不同的体系结构的页大小是不同的,有些体系结构甚至可以支持多种不同的页大小,在ARM中,就可以支持3种页大小,其中S3C2410的页大小为4KB。

2、内核物理页结构

内核的物理页结构定义在<linux/mm.h>中,它是一个构造数据类型—结构体,其结构体定义如下:

struct page{

/*页状态标记*/

page_flags_t flages;

/*页引用标记*/

atomic_t _count;

/*页映射计数,并且限制页反向映射*/

atomic_t _mapcount;

/*私有页标记*/

unsigned long private;

/*指向该物理页相关的结构*/

struct_address_space *mapping;

/*页映射偏移*/

pgoff_t index;

/*页换出队列*/

struct list_head lru;

/*页虚拟地址*/

void *virtual;

};

下面从语法角度介绍这些基本数据类型中的重要参数。

(1)flags

flags域是用于存放页的状态的,它的类型标识符为“page_flags_t”,可以看出,这是一个自定义的标识符,通常是由typedef来定义的。读者可以继续在该文件中查找,可以发现有以下定义:

typedf unsighed long page_flags_t;

可以看到,“page_flags_t"实际上是一个“unsigned long ”型32位的数据类型。那么,为什么在此处要设置一个32位的数据类型呢?原因在于,flag是用于页得状态的,它其中的每一位都单独表示一种状态,所以它可以同时表示出32种不同的状态。这些状态标志定义在<linux/page_flags.h>中,如下所示:

#define PG_locked 0 /*页被锁*/

#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 /*页缓存*/

#define PG_arch 8 /*页被检查*/

#define PG_reserved 10 /*页保留*/

#define PG_arch_1 9 /*一级页*/

#define PG_private 11 /*私有页*/

#define PG_writeback 12 /*页写回*/

#define PG_nosave 13 /*该页不安全*/

#define PG_compound 14 /*页响应*/

#define PG_swapcache 15 /*页换出在高速缓存中*/

#define PG_mappedtodisk 16 /*在磁盘中有该快*/

#define PG_reclaim 17 /*页声明*/

#define PG_nosave_free 18 /*页空闲*/

#define PG_uncached 19 /*页未在cache中命中*/

这里定义了19个状态,因此,安排一个32位的整数可以给今后的升级留有空间。

(2)_count和_mapcount

_count和_mapcount分别是页引用计数和页映射计数,它们的类型都是“atomic_t",同“atomic_t”,同“page_flags_t”一样,这个类型标识符也是自定义的,定义其的文件在</include/asm-arm/atomic.h>中,如下所示:

typedef struct {volatile int counter;}atomic_t;

可以看到,typedef不仅可以为基本数据类型取新名,也可以为构造数据类型取名。

(3)virtual

virtual是一个空指针,它用于指明页的虚拟地址。可以看到,使用指针来表示地址是非常恰当的。有些情况下,一些内存(即所谓的高端内存)并不永远地映射到内核空间上,这是virtual的值为NULL。

在这时为什么要用空指针呢?由于在此处,virtual用于表明一个地址而不是用于指示任何其他类型的数据,所以是使用空指针这一中立类型的指针是最合适的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: