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

本文章将带读者走进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用于表明一个地址而不是用于指示任何其他类型的数据,所以是使用空指针这一中立类型的指针是最合适的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值