uclinux初始化---------2
巫马修为
2023-12-01
asmlinkage void __init start_kernel(void)
{
char * command_line;
extern char saved_command_line[];
/*
* Interrupts are still disabled. Do necessary setups, then
* enable them
*/
lock_kernel();
printk(linux_banner);
setup_arch(&command_line);
printk("Kernel command line: %s/n", saved_command_line);
parse_options(command_line);
.....
。。。
}
下面我们开始分析start_kernel这段代码,主要是三个函数
/*
* Getting the big kernel lock.
*
* This cannot happen asynchronously,
* so we only need to worry about other
* CPU's.
*/
extern __inline__ void lock_kernel(void)
{
if (!++current->lock_depth)
spin_lock(&kernel_flag);
}
kernel_flag是一个内核大自旋锁,所有进程都通过这个大锁来实现向内核态的迁移。
只有获得这个大锁的处理器可以进入内核(如中断处理)。
这个函数相当简单,它获得全局内核锁--在任何一对lock_kernel/unlock_kernel函数里至多可以有一个CPU。
进程的lock_depth成员初始化为-1(参见kerenl/fork.c)。在它小于0时(若小于0则恒为-l),进程不拥有内核锁;当大于或等于0时,进程得到内核锁。
对于单cpu,该函数为空
void __init setup_arch(char **cmdline_p)
{
struct param_struct *params = NULL;
struct machine_desc *mdesc;
char *from = default_command_line;
int bootmap_size;
unsigned long memory_start = (unsigned long)&_end_kernel;
ROOT_DEV = MKDEV(0, 255);
setup_processor();
在该函数中,主要通过
for (list = &__proc_info_begin; list < &__proc_info_end ; list++)
if ((processor_id & list->cpu_mask) == list->cpu_val)
break;
这样一个循环来在..proc.info段中寻找匹配的processor_id,processor_id在前面的head_armv.S中设置
mdesc = setup_architecture(machine_arch_type);//获得体系结构的信息
machine_name = mdesc->name;
if (mdesc->soft_reboot)
reboot_setup("s");
if (mdesc->param_offset)
params = (struct param_struct*)
(phys_to_virt(mdesc->param_offset));
/*
* Do the machine-specific fixups before we parse the
* parameters or tags.
*/
if (mdesc->fixup)
mdesc->fixup(mdesc, params, &from, &meminfo);
分析传入的参数
if (params) {
struct tag *tag = (struct tag *)params;
/*
* Is the first tag the CORE tag? This differentiates
* between the tag list and the parameter table.
*/
if (tag->hdr.tag == ATAG_CORE)
parse_tags(mdesc->tagtable, mdesc->tagsize, tag);
else
parse_params(params);
}
meminfo结构表明了uclinux的内存情况
if (meminfo.nr_banks == 0) {
meminfo.nr_banks = 1;
meminfo.bank[0].start = PAGE_OFFSET;//PHYS_OFFSET;
meminfo.bank[0].size = MEM_SIZE;
}
初始化为一个bank,起始地址PAGE_OFFSET,大小MEM_SIZE
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;
memcpy(saved_command_line, from, COMMAND_LINE_SIZE);
saved_command_line[COMMAND_LINE_SIZE-1] = '/0';
如果命令行中有参数mem=size@start,那么我们将更新meminfo,之后,cmdline_p == "root=/dev/rom0"
parse_cmdline(&meminfo, cmdline_p, from);
bootmem_init(&meminfo); 初始化bootmem
paging_init(&meminfo, mdesc); // mem_map is set up here!
request_standard_resources(&meminfo, mdesc);//建立资源链表
/*
* Set up various architecture-specific pointers
*/
设定初始化irq的函数
init_arch_irq = mdesc->init_irq;
是否支持keyboard和显示设备,他们是用来做虚拟终端
#ifdef CONFIG_VT
#if defined(CONFIG_VGA_CONSOLE)
conswitchp = &vga_con;
#elif defined(CONFIG_DUMMY_CONSOLE)
conswitchp = &dummy_con;
#endif
#endif
}
void __init bootmem_init(struct meminfo *mi)
{
struct node_info node_info[NR_NODES], *np = node_info;
unsigned int bootmap_pages, bootmap_pfn, map_pg;
int node, initrd_node;
bootmap_pages = find_memend_and_nodes(mi, np);
注:通过上述操作,bootmap_pages设置了描述所有内存使用情况所需要的pages,并且在该函数中初始化了np[0]的内容。
bootmap_pfn = find_bootmap_pfn(0, mi, bootmap_pages);
注:通过上述操作,bootmap_pfn设置了bootmem所在的初始页号。也就是说从bootmap_pfn到bootmap_pfn + bootmap_pages的内存页被用来描述初始化的时候的内存的用用情况
initrd_node = check_initrd(mi); //do nothing
map_pg = bootmap_pfn;
np += numnodes - 1;
for (node = numnodes - 1; node >= 0; node--, np--) {
/*
* If there are no pages in this node, ignore it.
* Note that node 0 must always have some pages.
*/
if (np->end == 0) {
if (node == 0)
BUG();
continue;
}
/*
* Initialise the bootmem allocator.
*/
init_bootmem_node(NODE_DATA(node), map_pg, np->start, np->end);
注:在该函数中初始化contig_page_data中的struct bootmem_data *bdata
bdata->node_bootmem_map = bootmem的启示地址
bdata->node_boot_start = 本节点物理内存的开始
bdata->node_low_pfn =本节点物理内存的结尾
同时保留了所有的页面,使得所有内存不能使用,不过在下面的函数中将会放开。
但是在free_bootmem_node_bank(node, mi);中设置所有内存可以分配
free_bootmem_node_bank(node, mi);
map_pg += np->bootmap_pages;
/*
* If this is node 0, we need to reserve some areas ASAP -
* we may use bootmem on node 0 to setup the other nodes.
*/
if (node == 0)
reserve_node_zero(bootmap_pfn, bootmap_pages);
注意:在该函数中,保留了部分内存不能被分配,这些内存快包括:
reserve_bootmem_node(pgdat, __pa(&_stext), &_end - &_stext); 内核占用
reserve_bootmem_node(pgdat, bootmap_pfn << PAGE_SHIFT,
bootmap_pages << PAGE_SHIFT); bootmem占用
if (map_pg != bootmap_pfn + bootmap_pages)
BUG();
}