start_kernel()注解2
2010年06月17日
/*
Setup_arch()这个函数根据你的处理器,还有你的硬件平台设置你的系统,并解析Linux系统的命令行,设置0号进程,即Swapper进程的内在描述结构INIt_MM,系统内存管理初始化,统计并注册系统各种资源,还有其它一些相关的初始化
*/
setup_arch(&command_line)
{
void __init setup_arch(char **cmdline_p)
{
struct tag *tags = (struct tag *)&init_tags;
struct machine_desc *mdesc;
char *from = default_command_line;
setup_processor()
{
static void __init setup_processor(void)
{
extern struct proc_info_list __proc_info_begin, __proc_info_end;
struct proc_info_list *list;
/*
* locate processor in the list of supported processor
* types. The linker builds this table for us from the
* entries in arch/arm/mm/proc-*.S
*/
/*
从所支持的处理器类型表中找出所需要的处理器,利用Proc-*.S里面的函数,链接器会为我们创建这个表格,根据汇编代码中获取的ARM处理器的主ID寄存器的值processor_id,从Proc.info中找到该处理器对应的处理器信息结构proc_info_list变量,
*/
for (list = &__proc_info_begin; list cpu_mask) == list->cpu_val)//
break;
/*
* If processor type is unrecognised, then we
* can do nothing...
*/
/*
*如果处理器类型没有被认可,那么我们不做任何事情,
*/
if (list >= &__proc_info_end) {
printk("CPU configuration botched (ID %08x), unable "
"to continue.\n", processor_id);
while (1);
}
//如果被认可,我们保存CPU的名字到全局变量cpu_name中
cpu_name = list->cpu_name;
#ifdef MULTI_CPU
//把该处理器的处理函数结构指针保存
processor = *list->proc;
#endif
#ifdef MULTI_TLB
//保存快表操作函数组指针
cpu_tlb = *list->tlb;
#endif
#ifdef MULTI_USER
//保存处理器用户空间操作函数组结构指针
cpu_user = *list->user;
#endif
#ifdef MULTI_CACHE
//保存Cache操作函数组结构指针
cpu_cache = *list->cache;
#endif
//打印处理器名,ID,处理器的修正版本,体系结构信息
printk("CPU: %s [%08x] revision %d (ARMv%s)\n",
cpu_name, processor_id, (int)processor_id & 15,
proc_arch[cpu_architecture()]);
dump_cpu_info()
{
static void __init dump_cpu_info(void)
{
//读出处理器的ID
unsigned int info = read_cpuid(CPUID_CACHETYPE);
//打印处理器catche信息
if (info != processor_id) {
//以下是打印catche相关信息,如类型,组织形式,容量,块大小,相连性,
printk("CPU: D %s %s cache\n", cache_is_vivt() ? "VIVT" : "VIPT",
cache_types[CACHE_TYPE(info)]);
if (CACHE_S(info)) {
dump_cache("CPU: I cache", CACHE_ISIZE(info));
dump_cache("CPU: D cache", CACHE_DSIZE(info));
} else {
dump_cache("CPU: cache", CACHE_ISIZE(info));
}
}
}
};
//把它的处理器架构名字字符串arch_name + “L”传给system_utsname.machine,L是小端,B是大端 ENDIANNESS是小端
sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
//把体系架构版本字符串Elf_name + “L”传给elf_platform
sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
elf_hwcap = list->elf_hwcap;//硬件性能标志字传到全局变量中
//刚才保存过的processor是该处理器的函数组结构变量,调用_proc_init()初始化函数
cpu_proc_init()
{
processor._proc_init()
};
};
// machine_arch_type:系统体系结构类型,定义了当前系统硬件平台编号,从.arch.info(体系结构信息表)中找到该平台的结构描述结构变量machine_desc,之后传给局部变量Mdesc
mdesc = setup_machine(machine_arch_type)
{
static struct machine_desc * __init setup_machine(unsigned int nr)
{
extern struct machine_desc __arch_info_begin, __arch_info_end;
struct machine_desc *list;
/*
* locate architecture in the list of supported architectures.
从所支持的体系结构表中找出本体系结构
*/
for (list = &__arch_info_begin; list nr == nr)//平台编号相同说明找到
break;
/*
* If the architecture type is not recognised, then we
* can co nothing...
如果体系结构未被认可,啥也不做,
*/
if (list >= &__arch_info_end) {
printk("Architecture configuration botched (nr %d), unable "
"to continue.\n", nr);
while (1);
}
printk("Machine: %s\n", list->name);//打印体系结构 名字
return list;
}
};
machine_name = mdesc->name; //保存体系结构到全局变量中
if (mdesc->soft_reboot) //如果soft_reboot不为0,将reboot_mode设为“S”说明是软件重启动,硬件重启动reboot_mode为“H”[b][/b]
reboot_setup("s")
{
int __init reboot_setup(char *str)
{
reboot_mode = str[0];
return 1;
}
};
//如果param_offset 不为0,说明在系统内在基址+ param_offset处保存了[b]Bootloader[/b]中设置并传过来的系统参数,保存在这里的可以是老参数Param_stuct,也可以是新参数Tag
if (mdesc->param_offset)
tags = phys_to_virt(mdesc->param_offset)
{
#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
#define PHYS_OFFSET (0x30000000UL)
#define PAGE_OFFSET (0xc0000000UL)
};
2.6.10是老参数,我们会将它转成新的Tag 参数
/*
* If we have the old style parameters, convert them to
* a tag list. //如果我们用的是旧格式参数,将他们转化成新格式的
*/
if (tags->hdr.tag != ATAG_CORE)
convert_to_tag_list(tags);// 将他们转化成新格式的,这里会将其转成连续存放 的新格式参数,
if (tags->hdr.tag != ATAG_CORE)
tags = (struct tag *)&init_tags;//如果param_offset[b]是0,那么就用默认参数[/b]
if (mdesc->fixup) //成员函数有定义,调用之,做一些前期补充初始化并设置系统参数,这个函数很少定义而已,
mdesc->fixup(mdesc, tags, &from, &meminfo);
if (tags->hdr.tag == ATAG_CORE) {//查看系统是否设置了核心参数(根文件系统是否是只读,内存页大小,根文件系统设备号)
if (meminfo.nr_banks != 0)// 检查内存信息,不=0,说明前面调用过Fixup(),
squash_mem_tags(tags)
{
void __init squash_mem_tags(struct tag *tag)
{ //将内存参数的结构(标签为ATAG_MEM)清除,其它参数不变
for (; tag->hdr.size; tag = tag_next(tag))
if (tag->hdr.tag == ATAG_MEM)
tag->hdr.tag = ATAG_NONE;
}
};
//分析连续排放在struct tag 结构变量 的地址Tags处所有有效参数设置标签,从。Taglist区根据参数标签字找出每个有效参数标签对应的Struct tagtable结构变量,执行Struct tagtable结构变量中的标签,解析相应参数设置标签的内容,这个版本的内核中有11个这样的结构,
parse_tags(tags);
}
//设置Init_mm的成员变量,将Linux内核编译出来的代码段起始,结束地址,数据段结束地址,和整个内核结束地址分别保存到Start_code,end_code,end_data,Brk成员变量 中
init_mm.start_code = (unsigned long) &_text;
init_mm.end_code = (unsigned long) &_etext;
init_mm.end_data = (unsigned long) &_edata;
init_mm.brk = (unsigned long) &_end;
//将1024字节的系统默认命令行字符串全局变量default_command_line复制到系统备份命令行字符全局变量saved_command_line中,[b][/b]
memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
//然后解析default_command_line中的每个命令,系统认识的系统参数设置命令,都有一个对应的 对应的 Struct early_params全局结构变量,变量中定义了命令参数名以及对应的命令解析函数,所有这些Struct early_params全局结构变量都是通过,Early_param()宏定义的,它们被连续放置在Early_param区,一条命令行可以设置多个参数命令,两个参数命令之间只能用空格隔开,参数命令内部不能用空格隔开,同一参数的不同属性用逗号隔开
parse_cmdline(cmdline_p, from)
{
/*
* Initial parsing of the command line.
*/
static void __init parse_cmdline(char **cmdline_p, char *from)
{
char c = ' ', *to = command_line;
int len = 0;
for (;;) {
if (c == ' ') {
extern struct early_params __early_begin, __early_end;
struct early_params *p;
for (p = &__early_begin; p arg);
if (memcmp(from, p->arg, len) == 0) {
if (to != command_line)
to -= 1;
from += len;
p->fn(&from);
while (*from != ' ' && *from != '\0')
from++;
break;
}
}
}
c = *from++;
if (!c)
break;
if (COMMAND_LINE_SIZE <= ++len)
break;
*to++ = c;
}
*to = '\0';
*cmdline_p = command_line;
}
};
2010年06月17日
/*
Setup_arch()这个函数根据你的处理器,还有你的硬件平台设置你的系统,并解析Linux系统的命令行,设置0号进程,即Swapper进程的内在描述结构INIt_MM,系统内存管理初始化,统计并注册系统各种资源,还有其它一些相关的初始化
*/
setup_arch(&command_line)
{
void __init setup_arch(char **cmdline_p)
{
struct tag *tags = (struct tag *)&init_tags;
struct machine_desc *mdesc;
char *from = default_command_line;
setup_processor()
{
static void __init setup_processor(void)
{
extern struct proc_info_list __proc_info_begin, __proc_info_end;
struct proc_info_list *list;
/*
* locate processor in the list of supported processor
* types. The linker builds this table for us from the
* entries in arch/arm/mm/proc-*.S
*/
/*
从所支持的处理器类型表中找出所需要的处理器,利用Proc-*.S里面的函数,链接器会为我们创建这个表格,根据汇编代码中获取的ARM处理器的主ID寄存器的值processor_id,从Proc.info中找到该处理器对应的处理器信息结构proc_info_list变量,
*/
for (list = &__proc_info_begin; list cpu_mask) == list->cpu_val)//
break;
/*
* If processor type is unrecognised, then we
* can do nothing...
*/
/*
*如果处理器类型没有被认可,那么我们不做任何事情,
*/
if (list >= &__proc_info_end) {
printk("CPU configuration botched (ID %08x), unable "
"to continue.\n", processor_id);
while (1);
}
//如果被认可,我们保存CPU的名字到全局变量cpu_name中
cpu_name = list->cpu_name;
#ifdef MULTI_CPU
//把该处理器的处理函数结构指针保存
processor = *list->proc;
#endif
#ifdef MULTI_TLB
//保存快表操作函数组指针
cpu_tlb = *list->tlb;
#endif
#ifdef MULTI_USER
//保存处理器用户空间操作函数组结构指针
cpu_user = *list->user;
#endif
#ifdef MULTI_CACHE
//保存Cache操作函数组结构指针
cpu_cache = *list->cache;
#endif
//打印处理器名,ID,处理器的修正版本,体系结构信息
printk("CPU: %s [%08x] revision %d (ARMv%s)\n",
cpu_name, processor_id, (int)processor_id & 15,
proc_arch[cpu_architecture()]);
dump_cpu_info()
{
static void __init dump_cpu_info(void)
{
//读出处理器的ID
unsigned int info = read_cpuid(CPUID_CACHETYPE);
//打印处理器catche信息
if (info != processor_id) {
//以下是打印catche相关信息,如类型,组织形式,容量,块大小,相连性,
printk("CPU: D %s %s cache\n", cache_is_vivt() ? "VIVT" : "VIPT",
cache_types[CACHE_TYPE(info)]);
if (CACHE_S(info)) {
dump_cache("CPU: I cache", CACHE_ISIZE(info));
dump_cache("CPU: D cache", CACHE_DSIZE(info));
} else {
dump_cache("CPU: cache", CACHE_ISIZE(info));
}
}
}
};
//把它的处理器架构名字字符串arch_name + “L”传给system_utsname.machine,L是小端,B是大端 ENDIANNESS是小端
sprintf(system_utsname.machine, "%s%c", list->arch_name, ENDIANNESS);
//把体系架构版本字符串Elf_name + “L”传给elf_platform
sprintf(elf_platform, "%s%c", list->elf_name, ENDIANNESS);
elf_hwcap = list->elf_hwcap;//硬件性能标志字传到全局变量中
//刚才保存过的processor是该处理器的函数组结构变量,调用_proc_init()初始化函数
cpu_proc_init()
{
processor._proc_init()
};
};
// machine_arch_type:系统体系结构类型,定义了当前系统硬件平台编号,从.arch.info(体系结构信息表)中找到该平台的结构描述结构变量machine_desc,之后传给局部变量Mdesc
mdesc = setup_machine(machine_arch_type)
{
static struct machine_desc * __init setup_machine(unsigned int nr)
{
extern struct machine_desc __arch_info_begin, __arch_info_end;
struct machine_desc *list;
/*
* locate architecture in the list of supported architectures.
从所支持的体系结构表中找出本体系结构
*/
for (list = &__arch_info_begin; list nr == nr)//平台编号相同说明找到
break;
/*
* If the architecture type is not recognised, then we
* can co nothing...
如果体系结构未被认可,啥也不做,
*/
if (list >= &__arch_info_end) {
printk("Architecture configuration botched (nr %d), unable "
"to continue.\n", nr);
while (1);
}
printk("Machine: %s\n", list->name);//打印体系结构 名字
return list;
}
};
machine_name = mdesc->name; //保存体系结构到全局变量中
if (mdesc->soft_reboot) //如果soft_reboot不为0,将reboot_mode设为“S”说明是软件重启动,硬件重启动reboot_mode为“H”[b][/b]
reboot_setup("s")
{
int __init reboot_setup(char *str)
{
reboot_mode = str[0];
return 1;
}
};
//如果param_offset 不为0,说明在系统内在基址+ param_offset处保存了[b]Bootloader[/b]中设置并传过来的系统参数,保存在这里的可以是老参数Param_stuct,也可以是新参数Tag
if (mdesc->param_offset)
tags = phys_to_virt(mdesc->param_offset)
{
#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
#define PHYS_OFFSET (0x30000000UL)
#define PAGE_OFFSET (0xc0000000UL)
};
2.6.10是老参数,我们会将它转成新的Tag 参数
/*
* If we have the old style parameters, convert them to
* a tag list. //如果我们用的是旧格式参数,将他们转化成新格式的
*/
if (tags->hdr.tag != ATAG_CORE)
convert_to_tag_list(tags);// 将他们转化成新格式的,这里会将其转成连续存放 的新格式参数,
if (tags->hdr.tag != ATAG_CORE)
tags = (struct tag *)&init_tags;//如果param_offset[b]是0,那么就用默认参数[/b]
if (mdesc->fixup) //成员函数有定义,调用之,做一些前期补充初始化并设置系统参数,这个函数很少定义而已,
mdesc->fixup(mdesc, tags, &from, &meminfo);
if (tags->hdr.tag == ATAG_CORE) {//查看系统是否设置了核心参数(根文件系统是否是只读,内存页大小,根文件系统设备号)
if (meminfo.nr_banks != 0)// 检查内存信息,不=0,说明前面调用过Fixup(),
squash_mem_tags(tags)
{
void __init squash_mem_tags(struct tag *tag)
{ //将内存参数的结构(标签为ATAG_MEM)清除,其它参数不变
for (; tag->hdr.size; tag = tag_next(tag))
if (tag->hdr.tag == ATAG_MEM)
tag->hdr.tag = ATAG_NONE;
}
};
//分析连续排放在struct tag 结构变量 的地址Tags处所有有效参数设置标签,从。Taglist区根据参数标签字找出每个有效参数标签对应的Struct tagtable结构变量,执行Struct tagtable结构变量中的标签,解析相应参数设置标签的内容,这个版本的内核中有11个这样的结构,
parse_tags(tags);
}
//设置Init_mm的成员变量,将Linux内核编译出来的代码段起始,结束地址,数据段结束地址,和整个内核结束地址分别保存到Start_code,end_code,end_data,Brk成员变量 中
init_mm.start_code = (unsigned long) &_text;
init_mm.end_code = (unsigned long) &_etext;
init_mm.end_data = (unsigned long) &_edata;
init_mm.brk = (unsigned long) &_end;
//将1024字节的系统默认命令行字符串全局变量default_command_line复制到系统备份命令行字符全局变量saved_command_line中,[b][/b]
memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
saved_command_line[COMMAND_LINE_SIZE-1] = '\0';
//然后解析default_command_line中的每个命令,系统认识的系统参数设置命令,都有一个对应的 对应的 Struct early_params全局结构变量,变量中定义了命令参数名以及对应的命令解析函数,所有这些Struct early_params全局结构变量都是通过,Early_param()宏定义的,它们被连续放置在Early_param区,一条命令行可以设置多个参数命令,两个参数命令之间只能用空格隔开,参数命令内部不能用空格隔开,同一参数的不同属性用逗号隔开
parse_cmdline(cmdline_p, from)
{
/*
* Initial parsing of the command line.
*/
static void __init parse_cmdline(char **cmdline_p, char *from)
{
char c = ' ', *to = command_line;
int len = 0;
for (;;) {
if (c == ' ') {
extern struct early_params __early_begin, __early_end;
struct early_params *p;
for (p = &__early_begin; p arg);
if (memcmp(from, p->arg, len) == 0) {
if (to != command_line)
to -= 1;
from += len;
p->fn(&from);
while (*from != ' ' && *from != '\0')
from++;
break;
}
}
}
c = *from++;
if (!c)
break;
if (COMMAND_LINE_SIZE <= ++len)
break;
*to++ = c;
}
*to = '\0';
*cmdline_p = command_line;
}
};