




已阅读5页,还剩6页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1. 串口初始化过程 start_kernel() |- . |- setup_arch() |- . |- build_all_zonelists() |- page_alloc_init() |- . |- trap_init() |- . |- console_init() |- . |- mem_init() |- . - rest_init() - kernel_thread() - init() -do_basic_setup()1.1 console_init()drivers/char/tty_io.c/* 只作基本的初始化,详细的初始化在后面做 */void _init console_init(void) initcall_t *call; /* Setup the default TTY line discipline. */ (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); /* * set up the console device so that later boot sequences can * inform about problems etc. */#ifdef CONFIG_EARLY_PRINTK disable_early_printk();#endif call = _con_initcall_start; while (call _con_initcall_end) (*call)(); call+; 然后执行依次执行 .con_initcall.init 节中的函数,该节的每项为一个函数指针,使用宏 console_initcall(FUNC_NAME) 将函数指针填入,该宏定义于 include/linux/init.h:#define console_initcall(fn) static initcall_t _initcall_#fn _attribute_used_ _attribute_(_section_(.con_initcall.init)=fninitcall_t 为一函数指针: typedef int (*initcall_t)(void);如: console_initcall(serial8250_console_init) 则展开为:static initcall_t _initcall_serial8250_console_init = _attribute_used_ _attribute_(_section_(.con_initcall.init) = serial8250_console_init;即定义一个函数指针,使其指向 serial8250_console_init,并使用gcc的 _attribute_ 扩展,将其链接入.con_initcall.init 节,方便管理。一个典型的 .con_initcall.init 节的内容为:.Disassembly of section .con_initcall.init:80234f90 :80234f90: 802328e4 lb v1,10468(at) # 这是一个函数指针,指向serial8250_console_init80234f94 : 80234f94: 80232ce4 lb v1,11492(at).因此 console_init() 所做的,就是: console_init() |- tty_register_ldisc() /* Install a line discipline, drivers/char/tty_io.c */ |- serial8250_console_init() - early_uart_console_init()1.1.1 serial8250_console_initserial8250_console_init() 定义于 drivers/serial/8250.cstatic int _init serial8250_console_init(void) serial8250_isa_init_ports(); register_console(&serial8250_console); return 0;console_initcall(serial8250_console_init);static struct uart_8250_port serial8250_portsUART_NR;static void _init serial8250_isa_init_ports(void) struct uart_8250_port *up; static int first = 1; int i; if (!first) return; first = 0; for (i = 0; i port.line = i; spin_lock_init(&up-port.lock); init_timer(&up-timer); up-timer.function = serial8250_timeout; /* * ALPHA_KLUDGE_MCR needs to be killed. */ up-mcr_mask = ALPHA_KLUDGE_MCR; up-mcr_force = ALPHA_KLUDGE_MCR; up-port.ops = &serial8250_pops; for (i = 0, up = serial8250_ports; i ARRAY_SIZE(old_serial_port) & i port.iobase = old_serial_porti.port; up-port.irq = irq_canonicalize(old_serial_porti.irq); up-port.uartclk = old_serial_porti.baud_base * 16; up-port.flags = old_serial_porti.flags; up-port.hub6 = old_serial_porti.hub6; up-port.membase = old_serial_porti.iomem_base; up-port.iotype = old_serial_porti.io_type; up-port.regshift = old_serial_porti.iomem_reg_shift; if (share_irqs) up-port.flags |= UPF_SHARE_IRQ; serial8250_isa_init_ports()所做的事即使用old_serial_port来初始化struct uart_8250_port 结构数组 serial8250_ports. 这个old_serial_port定义为:static const struct old_serial_port old_serial_port = SERIAL_PORT_DFNS /* defined in asm/serial.h */;include/asm-mips/serial.h#define SERIAL_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 时:#ifdef CONFIG_HAVE_STD_PC_SERIAL_PORT#define STD_SERIAL_PORT_DEFNS /* UART CLK PORT IRQ 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 */#define STD_SERIAL_PORT_DEFNS#endif /* CONFIG_HAVE_STD_PC_SERIAL_PORTS */否则为空宏serial8250_isa_init_ports()后,serial8250_console_init() 调用 register_console(&serial8250_console) 注册一个struct console 结构:static struct uart_driver serial8250_reg;static struct console serial8250_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.c1.1.2 early_uart_console_init()drivers/serial/8250_early.cstatic struct console early_uart_console _initdata = .name = uart, .write = early_uart_write, .setup = early_uart_setup, .flags = CON_PRINTBUFFER, .index = -1,;static int _init early_uart_console_init(void) if (!early_uart_registered) register_console(&early_uart_console); early_uart_registered = 1; return 0;console_initcall(early_uart_console_init);和 serial8250_console_init() 类似,也是注册一个 console 结构,表示一个 uart console1.2 rest_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.1 do_basic_setup()到 do_basic_setup() 时,与体系结构相关的部分已经初始化完了,现在开始初始化设备了:init/main.cstatic void _init do_basic_setup(void) /* drivers will send hotplug events */ init_workqueues(); usermodehelper_init(); driver_init(); /* initialize driver model */ init_irq_proc(); do_initcalls(); /* 顺序执行 .initcall.init 节中的所有函数 */1.2.1 driver_init()driver_init() 定义于 drivers/base/init.c 主要完成 driver subsystem 的初始化:void _init driver_init(void) /* These are the core pieces */ devices_init(); buses_init(); classes_init(); firmware_init(); hypervisor_init(); /* These are also core pieces, but must come after the * core core pieces. */ platform_bus_init(); system_bus_init(); cpu_dev_init(); memory_dev_init(); attribute_container_init();这些函数主要调用 subsystem_register() 注册一个struct subsystem 结构,进入kobjects.1.2.2 do_initcall()这个于上面 console_init() 类似,其是顺序执行 .initcall.init 节中的所有函数:init/main.cextern initcall_t _initcall_start, _initcall_end;static void _init do_initcalls(void) initcall_t *call; int count = preempt_count(); for (call = _initcall_start; call _initcall_end; call+) char *msg = NULL; char msgbuf40; int result; if (initcall_debug) printk(Calling initcall 0x%p, *call); print_fn_descriptor_symbol(: %s(), (unsigned long) *call); printk(n); result = (*call)(); if (result & result != -ENODEV & initcall_debug) sprintf(msgbuf, error code %d, result); msg = msgbuf; if (preempt_count() != count) msg = preemption imbalance; preempt_count() = count; if (irqs_disabled() msg = disabled interrupts; local_irq_enable(); if (msg) printk(KERN_WARNING initcall at 0x%p, *call); print_fn_descriptor_symbol(: %s(), (unsigned long) *call); printk(: returned with %sn, msg); /* Make sure there is no pending stuff from the initcall sequence */ 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:#define pure_initcall(fn) _define_initcall(0,fn,1)#define core_initcall(fn) _define_initcall(1,fn,1)#define core_initcall_sync(fn) _define_initcall(1s,fn,1s)#define postcore_initcall(fn) _define_initcall(2,fn,2)#define postcore_initcall_sync(fn) _define_initcall(2s,fn,2s)#define arch_initcall(fn) _define_initcall(3,fn,3)#define arch_initcall_sync(fn) _define_initcall(3s,fn,3s)#define subsys_initcall(fn) _define_initcall(4,fn,4)#define subsys_initcall_sync(fn) _define_initcall(4s,fn,4s)#define fs_initcall(fn) _define_initcall(5,fn,5)#define fs_initcall_sync(fn) _define_initcall(5s,fn,5s)#define rootfs_initcall(fn) _define_initcall(rootfs,fn,rootfs)#define device_initcall(fn) _define_initcall(6,fn,6)#define device_initcall_sync(fn) _define_initcall(6s,fn,6s)#define late_initcall(fn) _define_initcall(7,fn,7)#define late_initcall_sync(fn) _define_initcall(7s,fn,7s)其优先级依次降低,优先级越高的,越靠前,则先被执行.在这个节的最后,可以看到调用串口相关的初始化函数:Disassembly of section .initcall.init:.80234f80 :80234f80: 80232910 lb v1,10512(at)80234f84 :80234f84: 802319c4 lb v1,6596(at)80234f88 :80234f88: 80231ae8 lb v1,6888(at)80234f8c :80234f8c: 80233140 lb v1,12608(at)因此: do_basic_setup() |- . |- driver_init() |- init_irq_proc() |- do_initcalls() |- . |- . |- serial8250_init() |- seqgen_init() - early_uart_console_switch() |- . - . serial8250_init()drivers/serial/8250.cstatic int _init serial8250_init(void) int ret, i; if (nr_uarts UART_NR) nr_uarts = UART_NR; printk(KERN_INFO Serial: 8250/16550 driver $Revision: 1.90 $ %d ports, IRQ sharing %sabledn, nr_uarts, share_irqs ? en : dis); for (i = 0; i dev); ret = platform_driver_register(&serial8250_isa_driver); - 注册时调用 serial8250_probe() if (ret = 0) goto out; platform_device_del(serial
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 住宅土地买卖合同协议书
- 汽车维修租赁合同协议书
- 租赁带牌小客车合同范本
- 买卖经营合作合同范本
- 超市购物卡采购合同范本
- 毕业生签约艺人合同范本
- 32条正规劳动合同范本
- 修船厂出租转让合同范本
- 厂房招租小面积合同范本
- 怎样签电子租赁合同协议
- 2025年发展对象考试试题库及参考答案
- 2025山西临汾市洪洞县招聘专职社区工作者58人考试备考试题及答案解析
- 《MySQL数据库教程》课件第一章数据库概述
- 2025年“中央八项规定”精神学习知识竞赛测试题库及答案
- 2025至2030年中国学前教育市场供需格局及未来发展趋势报告
- 1.1 空间和时间(教学课件)高中物理鲁科版必修第一册
- 桡骨茎突腱鞘炎的护理查房
- 2026届湖南省长沙市名校中考语文模试卷含解析
- 2025年中国药典培训试题及答案
- 部队兵器室管理课件
- 抖音完整种草链路
评论
0/150
提交评论