Linux内核及ARM的内存管理(续)

本文详细解析了ARM架构下Linux内核启动过程中两个关键函数__lookup_processor_type与__lookup_machine_type的工作原理。介绍了如何通过ARM汇编指令实现对处理器类型及机器类型的查找,并解释了这些函数如何与硬件信息交互以初始化系统。

 

__lookup_processor_type函数:

 

__lookup_processor_type:

 ARM( adr r3, 3f )

 ARM( ldmda r3, {r5 - r7} )

 THUMB( adr r3, 3f+4 )

 THUMB( ldmdb r3, {r5 - r7} )

 THUMB( sub r3, r3, #4 )

sub r3, r3, r7 @ get offset between virt&phys

add r5, r5, r3 @ convert virt addresses to

add r6, r6, r3 @ physical address space

1: ldmia r5, {r3, r4} @ value, mask

and r4, r4, r9 @ mask wanted bits

teq r3, r4

beq 2f

add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)

cmp r5, r6

blo 1b

mov r5, #0 @ unknown processor

2: mov pc, lr

ENDPROC(__lookup_processor_type)

 

/*

 * Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for

 * more information about the __proc_info and __arch_info structures.

 */

.long __proc_info_begin

.long __proc_info_end

3: .long .

.long __arch_info_begin

.long __arch_info_end

 

 

语句“adr r3, 3f”向前寻找到标号3的地址,赋给寄存器r3;

语句“ldmda r3, {r5 - r7}”将寄存器r3所指地址处的数据分别读入r5,r6,r7,由于ldmda是“过后减少装载”方式,因此r6与r7分别读入的应是__proc_info_end和__proc_info_begin;

 

函数返回后,有一个操作:

 

movs r10, r5

 

将寄存器r5中的proc_info入口地址保存在寄存器r10中,这是为了后来调用__create_page_tables准备的

 

 

__lookup_machine_type函数:

 

__lookup_machine_type:

adr r3, 3b

ldmia r3, {r4, r5, r6}

sub r3, r3, r4 @ get offset between virt&phys

add r5, r5, r3 @ convert virt addresses to

add r6, r6, r3 @ physical address space

1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type

teq r3, r1 @ matches loader number?

beq 2f @ found

add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc

cmp r5, r6

blo 1b

mov r5, #0 @ unknown machine

2: mov pc, lr

ENDPROC(__lookup_machine_type)

 

此函数紧挨着__lookup_processor_type,与__lookup_processor_type共用标号3,不同的是语句“adr r3, 3b”为向后查找标号3,将标号3的地址赋给寄存器r3;

接下来的语句“ldmia r3, {r4, r5, r6}”采用了过后增加装载指令查表,将__arch_info_begin、__arch_info_end地地址分别装入寄存器r5、r6;

 

回顾一下标号3:

 

/*

 * Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for

 * more information about the __proc_info and __arch_info structures.

 */

.long __proc_info_begin

.long __proc_info_end

3: .long .

.long __arch_info_begin

.long __arch_info_end

 

可见,__lookup_processor_type函数通过ldmda指令查找__proc_info_表格,__lookup_machine_type函数则通过ldmia指令查找__arch_info_表格。

 

 

__arch_info_表格的生成,可见arch/arm/include/asm/mach/arch.h文件中定义的宏MACHINE_START:

 

/*

 * Set of macros to define architecture features.  This is built into

 * a table by the linker.

 */

#define MACHINE_START(_type,_name) /

static const struct machine_desc __mach_desc_##_type /

 __used /

 __attribute__((__section__(".arch.info.init"))) = { /

.nr = MACH_TYPE_##_type, /

.name = _name,

 

#define MACHINE_END /

};

 

以TI OMAP3 参考板为例,MACHINE_START表格的具体填写,在arch/arm/mach-omap2/board-zoom2.c文件中:

 

MACHINE_START(OMAP_ZOOM2, "OMAP ZOOM2 board")

.phys_io = 0x48000000,

.io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,

.boot_params = 0x80000100,

.map_io = omap_ldp_map_io,

.init_irq = omap_ldp_init_irq,

.init_machine = omap_ldp_init,

.timer = &omap_timer,

MACHINE_END

 

 

 

回到__lookup_machine_type函数,寄存器r1在kernel入口时已被赋予了type的数值,从u-boot代码include/asm-arm/mach-types.h文件中定义:

 

#define MACH_TYPE_OMAP_ZOOM2          1967

 

可知,boot向Kernel传入的数据应为1967,kernel中,OMAP_ZOOM2对应的type值由脚本文件arch/arm/tools/mach-types指定,该脚本中,行

 

omap_zoom2 MACH_OMAP_ZOOM2 OMAP_ZOOM2 1967

 

指定OMAP_ZOOM2对应的type值为1967,因此,函数__lookup_machine_type的查表过程成功,寄存器r5中返回ZOOM2对应信息的数据结构首地址;函数返回后,有一个操作:

 

movs r8, r5

 

将寄存器r5中的__arch_info入口地址保存在寄存器r8中,这也是为了后来调用__create_page_tables准备的

 

 

需要关注的数据结构machine_desc(在文件arch/arm/include/asm/mach/arch.h中定义):

struct machine_desc {

/*

* Note! The first four elements are used

* by assembler code in head.S, head-common.S

*/

unsigned int nr; /* architecture number */

unsigned int phys_io; /* start of physical io */

unsigned int io_pg_offst; /* byte offset for io 

* page tabe entry */

 

const char *name; /* architecture name */

unsigned long boot_params; /* tagged list */

 

unsigned int video_start; /* start of video RAM */

unsigned int video_end; /* end of video RAM */

 

unsigned int reserve_lp0 :1; /* never has lp0 */

unsigned int reserve_lp1 :1; /* never has lp1 */

unsigned int reserve_lp2 :1; /* never has lp2 */

unsigned int soft_reboot :1; /* soft reboot */

void (*fixup)(struct machine_desc *,

struct tag *, char **,

struct meminfo *);

void (*map_io)(void);/* IO mapping function */

void (*init_irq)(void);

struct sys_timer *timer; /* system tick timer */

void (*init_machine)(void);

};

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值