注:
原文出自taoyuetao大侠的博客上:
http://www.eetop.cn/blog/html/45/11145_itemid_1396.html
小弟参考之研究s3c2410相关代码,然后做了稍微的修改,作为一个学习笔记,方便以后的学习,也希望对后人有所帮助^_^
前面一篇文章,简单介绍了内核启动的汇编主流程,这篇介绍其中调用的汇编子函数__lookup_processor_type
函数__lookup_processor_type介绍:
内核中使用了一个结构struct proc_info_list,用来记录处理器相关的信息,该结构定义在
kernel/include/asm-arm/procinfo.h头文件中。
/*
*
Note! struct processor is always defined
if we're
*
using MULTI_CPU, otherwise this entry is unused,
*
but still exists.
*
*
NOTE! The following structure is defined by assembly
*
language, NOT C code. For more
information, check:
*
arch/arm/mm/proc-*.S and arch/arm/kernel/head.S
*/
struct proc_info_list {
unsigned
int cpu_val;
unsigned
int cpu_mask;
unsigned
long __cpu_mmu_flags; /* used by head.S */
unsigned
long __cpu_flush; /* used by head.S */
const
char *arch_name;
const
char *elf_name;
unsigned
int elf_hwcap;
const
char *cpu_name;
struct
processor *proc;
struct
cpu_tlb_fns *tlb;
struct
cpu_user_fns *user;
struct
cpu_cache_fns *cache;
};
在arch/arm/mm/proc-arm920.S文件中定义了所有和arm920有关的proc_info_list,我们使用的arm920定义如下:
.section
".proc.info.init", #alloc, #execinstr
.type __arm920_proc_info,#object
__arm920_proc_info:
.long 0x41009200
.long 0xff00fff0
.
.
由于.section指示符,上面定义的__arm920_proc_info信息在编译的时候被放到了.proc.info段中,这是由linux的链接脚本文件arch/arm/kernel/vmlinux.lds指定的,参考如下:
SECTIONS
{
.
= TEXTADDR;
.init
: { /* Init code and data */
_stext
= .;
_sinittext
= .;
*(.init.text)
_einittext
= .;
__proc_info_begin
= .;
*(.proc.info.init)
__proc_info_end
= .;
.
.
这里的符号__proc_info_begin指向.proc.info的起始地址,而符号__proc_info_end指向.proc.info的结束地址。后面就会引用这两个符号,来指向.proc.info这个段。
下面来来看看函数的源代码,为了分析方便将函数按行进行编号,其中17-18行就是前面提到的对.proc.info的引用,
第2行将19行的地址放到寄存器r3中,adr是小范围的地址读取伪指令。
第3行将r3所指向的数据区的数据读出到r5,r6,r9,执行结果是
R5=__proc_info_begin,r6=__proc_info_end,r9=第19行的地址
用仿真器查看:
r5=0xc0018664
r6=0xc0018694
r9=0xc0008324(为何是0xc0008324而不是0x30008324???)
第4行算出虚、实地址的偏移,
第5-6行的结果应该是r5指向__proc_info_begin的实地址,r6指向__proc_info_end的实地址。
第7行读取cpu的id,这是一个协处理器指令,将processor ID存储在r9中。
第8行将r5指向的__arm920_proc_info开始的数据读出放到寄存器r3,r4,结果r3=0x41009200 (cpu_val),r4=0xff00fff0 (cpu_mask)。
第9-10行将读出的id和结构中的id进行比较,如果id相同则返回,返回时r9存储
processor ID,如果id不匹配,则将指针r10增加PROC_INFO_SZ (proc_info_list结构的长度,在这等于48),如果r5小于r6指定的地址,也就是
__proc_info_end,则继续循环比较下一个proc_info_list中的id,如第11-14行的代码,如果查找到__proc_info_end,仍未找到一个匹配的id,则将r5清零并返回,如15-16行,也就是说如果函数执行成功则r5指向匹配的proc_info_list结构地址,如果函数返回错误则r5为0。
/*
*
Read processor ID register (CP#15, CR0), and look up in the linker-built
*
supported processor list. Note that we
can't use the absolute addresses
*
for the __proc_info lists since we aren't running with the MMU on
*
(and therefore, we are not in the correct address space). We have to
*
calculate the offset.
*
*
Returns:
* r3, r4, r6 corrupted
* r5 = proc_info pointer in physical address
space
* r9 = cpuid
*/
.type __lookup_processor_type, %function
1 __lookup_processor_type:
2 adr r3,
3f
3 ldmda r3,
{r5, r6, r9}
4 sub r3,
r3, r9 @ get offset between
virt&phys
5 add r5,
r5, r3 @ convert virt addresses
to
6 add r6,
r6, r3 @ physical address space
7 mrc p15,
0, r9, c0, c0 @ get processor id
8 1: ldmia r5,
{r3, r4} @ value, mask
9 and r4,
r4, r9 @ mask wanted bits
10 teq r3,
r4
11 beq 2f
12 add r5,
r5, #PROC_INFO_SZ @
sizeof(proc_info_list)
13 cmp r5,
r6
14 blo 1b
15 mov r5,
#0 @ unknown processor
16 2: mov pc,
lr
/*
*
Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for
*
more information about the __proc_info and __arch_info structures.
*/
17 .long __proc_info_begin
18 .long __proc_info_end
19 3: .long .
20 .long __arch_info_begin
21 .long __arch_info_end
posted on 2007-07-24 20:50
lfc 阅读(1567)
评论(0) 编辑 收藏 引用