i++,up++){
up->port.iobase =old_serial_port[i].port;
up->port.irq =irq_canonicalize(old_serial_port[i].irq);
up->port.uartclk=old_serial_port[i].baud_base*16;
up->port.flags =old_serial_port[i].flags;
up->port.hub6 =old_serial_port[i].hub6;
up->port.membase=old_serial_port[i].iomem_base;
up->port.iotype =old_serial_port[i].io_type;
up->port.regshift=old_serial_port[i].iomem_reg_shift;
if(share_irqs)
up->port.flags|=UPF_SHARE_IRQ;
}
}
serial8250_isa_init_ports()所做的事即使用old_serial_port来初始化structuart_8250_port结构数组serial8250_ports.这个old_serial_port定义为:
staticconststructold_serial_portold_serial_port[]={
SERIAL_PORT_DFNS /*definedinasm/serial.h*/
};
[include/asm-mips/serial.h]
#defineSERIAL_PORT_DFNS \
DDB5477_SERIAL_PORT_DEFNS \
EV64120_SERIAL_PORT_DEFNS \
IP32_SERIAL_PORT_DEFNS \
JAZZ_SERIAL_PORT_DEFNS \
STD_SERIAL_PORT_DEFNS \
MOMENCO_OCELOT_G_SERIAL_PORT_DEFNS \
MOMENCO_OCELOT_C_SERIAL_PORT_DEFNS \
MOMENCO_OCELOT_SERIAL_PORT_DEFNS \
MOMENCO_OCELOT_3_SERIAL_PORT_DEFNS \
BCM947XX_SERIAL_PORT_DEFNS \
BCM56218_SERIAL_PORT_DEFNS
这个根据具体的平台配置,使用相应的宏定义.如当CONFIG_HAVE_STD_PC_SERIAL_PORT时:
#ifdefCONFIG_HAVE_STD_PC_SERIAL_PORT
#defineSTD_SERIAL_PORT_DEFNS \
/*UARTCLK PORTIRQ FLAGS */ \
{0,BASE_BAUD,0x3F8,4,STD_COM_FLAGS},/*ttyS0*/\
{0,BASE_BAUD,0x2F8,3,STD_COM_FLAGS},/*ttyS1*/\
{0,BASE_BAUD,0x3E8,4,STD_COM_FLAGS},/*ttyS2*/\
{0,BASE_BAUD,0x2E8,3,STD_COM4_FLAGS},/*ttyS3*/
#else/*CONFIG_HAVE_STD_PC_SERIAL_PORTS*/
#defineSTD_SERIAL_PORT_DEFNS
#endif/*CONFIG_HAVE_STD_PC_SERIAL_PORTS*/
否则为空宏
serial8250_isa_init_ports()后,serial8250_console_init()调用register_console(&serial8250_console)注册一个structconsole结构:
staticstructuart_driverserial8250_reg;
staticstructconsoleserial8250_console={
.name ="ttyS",
.write =serial8250_console_write,
.device =uart_console_device,
.setup =serial8250_console_setup,
.flags =CON_PRINTBUFFER,
.index =-1,
.data =&serial8250_reg,
};
其用来描述一个serial8250的console.
这个register_console()定义于[kernel/printk.c]
1.1.2early_uart_console_init()
[drivers/serial/8250_early.c]
staticstructconsoleearly_uart_console__initdata={
.name ="uart",
.write=early_uart_write,
.setup=early_uart_setup,
.flags=CON_PRINTBUFFER,
.index=-1,
};
staticint__initearly_uart_console_init(void)
{
if(!
early_uart_registered){
register_console(&early_uart_console);
early_uart_registered=1;
}
return0;
}
console_initcall(early_uart_console_init);
和serial8250_console_init()类似,也是注册一个console结构,表示一个uartconsole
1.2rest_init()
rest_init()
|-----...
|-----smp_prepare_cpus(max_cpus)
|-----do_pre_smp_initcalls()
|-----smp_init()
|-----sched_init_smp()
|-----cpuset_init_smp()
|-----do_basic_setup()
|-----...
`-----init_post()
1.2.1do_basic_setup()
到do_basic_setup()时,与体系结构相关的部分已经初始化完了,现在开始初始化设备了:
[init/main.c]
staticvoid__initdo_basic_setup(void)
{
/*driverswillsendhotplugevents*/
init_workqueues();
usermodehelper_init();
driver_init(); /*initializedrivermodel*/
init_irq_proc();
do_initcalls(); /*顺序执行.initcall.init节中的所有函数*/
}
1.2.1driver_init()
driver_init()定义于[drivers/base/init.c]主要完成driversubsystem的初始化:
void__initdriver_init(void)
{
/*Thesearethecorepieces*/
devices_init();
buses_init();
classes_init();
firmware_init();
hypervisor_init();
/*Thesearealsocorepieces,butmustcomeafterthe
*corecorepieces.
*/
platform_bus_init();
system_bus_init();
cpu_dev_init();
memory_dev_init();
attribute_container_init();
}
这些函数主要调用subsystem_register()注册一个structsubsystem结构,进入kobjects.
1.2.2do_initcall()
这个于上面console_init()类似,其是顺序执行.initcall.init节中的所有函数:
[init/main.c]
externinitcall_t__initcall_start[],__initcall_end[];
staticvoid__initdo_initcalls(void)
{
initcall_t*call;
intcount=preempt_count();
for(call=__initcall_start;call<__initcall_end;call++){
char*msg=NULL;
charmsgbuf[40];
intresult;
if(initcall_debug){
printk("Callinginitcall0x%p",*call);
print_fn_descriptor_symbol(":
%s()",
(unsignedlong)*call);
printk("\n");
}
result=(*call)();
if(result&&result!
=-ENODEV&&initcall_debug){
sprintf(msgbuf,"errorcode%d",result);
msg=msgbuf;
}
if(preempt_count()!
=count){
msg="preemptionimbalance";
preempt_count()=count;
}
if(irqs_disabled()){
msg="disabledinterrupts";
local_irq_enable();
}
if(msg){
printk(KERN_WARNING"initcallat0x%p",*call);
print_fn_descriptor_symbol(":
%s()",
(unsignedlong)*call);
printk(":
returnedwith%s\n",msg);
}
}
/*Makesurethereisnopendingstufffromtheinitcallsequence*/
flush_scheduled_work();
}
关于符号地址__initcall_start,__initcall_end的来源,则是由编译系统写在[arch/mips/kernel/vmlinux.lds]中:
......
__initcall_start=.;
.initcall.init:
{
*(.initcall0.init)*(.initcall0s.init)*(.initcall1.init)*(.initcall1s.init)*(.initcall2.init)*(.initcall2s.init)*(.initcall3.init)*(.initcall3s.init)*(.initcall4.init)*(.initcall4s.init)*(.initcall5.init)*(.initcall5s.init)*(.initcallrootfs.init)*(.initcall6.init)*(.initcall6s.init)*(.initcall7.init)*(.initcall7s.init)
}
__initcall_end=.;
......
链接时,会被替换为实际的地址矣.
写入.initcall.init节的函数指针,有一组辅助的宏定义于[include/linux/init.h]:
#definepure_initcall(fn) __define_initcall("0",fn,1)
#definecore_initcall(fn) __define_initcall("1",fn,1)
#definecore_initcall_sync(fn) __define_initcall("1s",fn,1s)
#definepostcore_initcall(fn) __define_initcall("2",fn,2)
#definepostcore_initcall_sync(fn)__define_initcall("2s",fn,2s)
#definearch_initcall(fn) __define_init