接触嵌入式开发也有两年多了,每天看着同样的启动信息似乎都有些麻木了,但上次寻找网络驱动时pan总就是从启动信息中追溯到了驱动源文件,于是想了解一下这些启动信息,对之前感觉熟悉但又不知甚解的东西做一个简单的跟踪,对以后的工作学习应该也有帮助。
Flash映射起始地址 进入0xf00000 uboot image
(该地址应该是由0x0000处的硬件配置字决定的)
Uboot是上电后执行的第一段程序,主要用于初始化处理器及外设,启动内核。
U-Boot 1.3.0-rc2 (Oct 19 2007 - 16:58:40)
U-Boot版本信息
U-Boot
image的入口点是start.S汇编代码,设置一些寄存器,时钟等操作都是在汇编中完成,然后进入board_init_f顺序执行下面的系列初始化函数,board_init_f位于u-boot-1.3.0-
rc3/lib_ppc/board.c中,是uboot所有C代码的第一处入口点,注意到这时候uboot是运行在rom中,只能使用很小的堆栈,并且无法修改全局变量。
MPC8272 Reset Status:
External Soft, External Hard
代码在
u-boot-1.3.0-rc3/cpu/mpc8260/cpu_init.c函数prt_8260_rsr()中
MPC8272 Clock
Configuration
- Bus-to-Core Mult 4x, VCO Div 2, 60x Bus Freq 25-75 , Core Freq
100-300
- dfbrg 1, corecnf 0x1a, busdf 3, cpmdf 1, plldf 0, pllmf 3, pcidf
5
- vco_out 400000000, scc_clk 100000000, brg_clk 25000000
- cpu_clk 400000000, cpm_clk 200000000, bus_clk 100000000
- pci_clk 33333333
打印出了主板,cpu的一些指标信息,代码在u-boot-1.3.0-rc3/cpu/mpc8260/speed.c函数prt_8260_clks()中
board_init_f完成一部分初始化工作后又跳转到汇编中,初始化堆栈,控制器等,再次进入C代码段是在board.c的board_init_r中,这时候已经是加载在内存中执行,可以正常得使用堆栈了。
CPU: MPC8272 (HiP7 Rev 14,
Mask 1.0 1K50M) at 400 MHz
Board: MSC7119RDK
I2C: ready
DRAM: 128 MB
FLASH: 16 MB
In: serial
Out: serial
Err: serial
Net: FCC1 ETHERNET, FCC2 ETHERNET
以上信息是由board_init_r函数检测,初始化,并打印,初始化看门狗之后进入common\main.c的main_loop函数中。
Hit any key to stop autoboot:
0
main_loop会延时一小段时间,按键进入u-boot设置,没有按键则进入正常启动流程,延时时间可以在此处修改。
Uboot设置中有两项主要配置,引导着接下来的启动过程。
1. bootcmd=bootm FF020000
无按键时就是执行该命令,uboot之前将flash的kernel映射在FF020000内存地址上,bootm也指向FF020000就能顺利启动linux内核。
2. bootargs=root=/dev/mtdblock3 rootfstype=jffs2 noinitrd
init=/etc/preinit console=ttyCPM0,115200n8
Linux内核启动参数,指定了根文件系统块(mtdblock3),文件系统类型(jffs2),内核执行的初始化进程名(preinit),串口参数。(之前有一次串口出问题,就是因为consolo的值配错了),Linux内核启动参数也有其他挺好玩的应用,都可以在此修改,比如设置panic=N,可以让内核在崩溃N秒后才重启。
## Booting image at ff020000
...
Image Name: Linux-2.6.14
Image Type: PowerPC Linux Kernel Image (gzip compressed)
Data Size: 1170641 Bytes = 1.1 MB
Load Address: 00000000
Entry Point: 00000000
Verifying Checksum ... OK
Uncompressing Kernel Image ... OK
以上信息是bootm的执行函数do_bootm打印的(common\cmd_bootm.c),实际上就是二进制内核文件的开头几个字节,而且注意到我们的内核是压缩内核,需要一次解压过程,解压后执行do_bootm_linux函数启动Linux内核。
-----------------------------------------Linux内核启动分割线---------------------------------
Linux内核的入口在init/main.c的start_kernel()函数中,初始化调度,中断,定时器等系列初始化操作都在该函数中。它主要完成剩余的与硬件平台相关的初始化工作,在进行一系列与内核相关的初始化后,调用第一个用户进程-init
进程并等待用户进程的执行,这样整个 Linux 内核便启动完毕。
Linux version 2.6.14
(huangzc@compiling-server) (gcc version 4.1.2) #3 PREEMPT Mon Dec7
13:58:26 CST 2009 以上信息保存在linux_banner常量中(init/version.c)
Freescale StarCore PowerPC
port
setup_arch()函数打印(arch/ppc/kernel/setup.c),ppc_md.setup_arch()回调原型在arch/ppc/syslib/m8260_setup.c的m8260_setup_arch(void)函数中,上述常量信息在arch/ppc/platforms/Msc7119rdk.h中,该文件是设备相关的,平台移植时的一大工作量应该就是修改这类文件。
setup_arch()函数是与体系结构相关的第一个初始化工作,对不同的体系结构来说该函数有不同的定义。它首先通过检测出来的处理器类型进行处理器内核的初始化,然后通过
bootmem_init()函数根据系统定义的 meminfo 结构进行内存结构的初始化,最后调用paging_init()开启
MMU,创建内核页表,映射所有的物理内存和
IO空间。
Staring set led to default
state
led初始化,set_default_led()函数中(arch/ppc/kernel/setup.c)
arch/ppc/syslib/m82xx_pci.c:
The PCI bus is 33333333 Mhz.
Waiting 1 second after deasserting RST...
pq2_find_bridges()函数调用pq2ads_setup_pci()完成pci初始化(arch/ppc/syslib/m82xx_pci.c)。
Built 1 zonelists
build_all_zonelists函数打印(mm/page_alloc.c)
Kernel command line:
root=/dev/mtdblock3 rootfstype=jffs2 noinitrd init=/etc/preinit
console=ttyCPM0,115200n8
start_kernel()重新打印出了Linux内核启动参数,内核启动异常时可以先核对该参数是否正确。
PID hash table entries: 1024
(order: 10, 16384 bytes)
pidhash_init()函数打印(kernel/pid.c),由函数也可以看出,进程id的分配查找用的是哈希算法
Warning: real time clock
seems stuck!
time_init()函数打印(kernel/time.c),初始化系统时钟。
Console: colour dummy device
80x25
console_init打印(drivers/char/tty_io.c),也是调用了系列回调。
Dentry cache hash table
entries: 32768 (order: 5, 131072 bytes)
Inode-cache hash table entries: 16384 (order: 4, 65536
bytes)
alloc_large_system_hash()函数打印(mm/page_alloc.c),分别在fs/dcache.c和fs/inode.c中调用。
Memory: 127232k available
(1900k kernel code, 584k data, 96k init, 0k highmem)
mem_init()函数打印(mm/init.c)
Mount-cache hash table
entries: 512
mnt_init()函数打印(fs/namespace.c)
NET: Registered protocol
family 16
net/netlink/af_netlink.c模块初始化,调用sock_register注册函数注册netlink系列回调
PCI: Probing PCI
hardware
arch/ppc/kernel/pci.c模块初始化,调用pcibios_init()函数打印
PCI: Cannot allocate resource
region 0 of device 0000:00:00.0
PCI: Cannot allocate resource region 1 of device
0000:00:00.0
在pcibios_init()函数中pcibios_allocate_resources打印。因为我们板没有提供PCI支持,所以alloc失败?
Generic PHY: Registered new
driver PHY模块初始化,注册了Generic
PHY这个通用PHY设备(drivers/net/phy/phy_device.c)
SCSI subsystem
initialized SCSI模块初始化,注册了scsi的系列函数方法(drivers/scsi/scsi.c)
JFFS2 version 2.2. (NAND) (C)
2001-2003 Red Hat, Inc.
jffs2文件系统初始化,通过register_filesystem等函数注册文件系统(fs/jffs2/super.c)
yaffs Dec 7 2009 13:57:00
Installing.
yaffs(yaffs2)文件系统初始化,打印的时间即为编译时间(fs/yaffs2/yaffs_fs.c)
Initializing Cryptographic
API
crypto模块初始化,完成crypto的系列内核函数(crypto/api.c)
Generic RTC Driver
v1.07
rtc模块初始化,注册基于misc的字符设备(drivers/char/genrtc.c)
Serial: CPM driver $Revision:
1.1.1.1 $ ttyCPM0 at MMIO
0xf0011a80 (irq = 4) is a CPM UART
serial模块初始化,通过tty_register_driver注册(driver/serial/cpm_uart/cpu_uart_core.c),并通过uart_configure_port()完成配置。
io scheduler noop
registered
io调度模块初始化,通过elv_register函数注册(drivers/block/noop-iosched.c)
Uniform Multi-Platform E-IDE
driver Revision: 7.00alpha2
ide: Assuming 33MHz system bus speed for PIO modes; override with
idebus=xx
IDE phys mem : fe000000...fe000200 (size 00000200)
ide模块初始化(drivers/ide/ide.c),先通过ide_system_bus_speed获取总线速率,然后调用init_ide_data初始化ide相关数据
hda: SanDisk SDCFJ-1024, CFA
DISK drive
ide0 at 0xfe001000-0xfe001007,0xfe00200c on irq 52
ideprobe模块初始化(drivers/ide/ide-probe.c),do_identify()函数打印hda相关信息,init_irq()注册相关中断
hda: max request size:
128KiB
hda: 2001888 sectors (1024 MB) w/1KiB Cache, CHS=1986/16/63
hda: cache flushes not supported
hda: hda1
idedisk模块初始化(drivers/ide/ide-disk.c),调用idedisk_setup()检测相关数据
SVX8016 flash device: 1000000
at ff000000
drivers/mtd/maps/msc7119rdk.c模块初始化,flash大小等信息都定义在msc7119rdk.h中
SVX8016: Found 1 x16 devices
at 0x0 in 16-bit bank
drivers/mtd/chips/cfi_probe.c函数cfi_probe_chip()打印
Amd/Fujitsu Extended Query
Table at 0x0040
driver/mtd/chips/cfi_util.c函数cfi_read_pri()打印
SVX8016: CFI does not contain
boot bank location. Assuming top.
number of CFI chips: 1
cfi_cmdset_0002: Disabling erase-suspend-program due to code
brokenness.
drivers/mtd/chips/cfi_cmdset_0002.c函数cfi_cmdset_0002()和cfi_amdstd_setup()打印。
Creating 7 MTD partitions on
"SVX8016":
0x00f00000-0x00f40000 : "uboot image"
0x00f40000-0x00f80000 : "uboot env"
0x00020000-0x00160000 : "kernel"
0x00160000-0x00f00000 : "file system"
0x00020000-0x00f00000 : "kernel+fs"
0x00f80000-0x01000000 : "config"
0x00000000-0x01000000 : "binary"
msc7119rdk模块调用函数add_mtd_partitions()完成mtd分区(drivers/mtd/mtdpart.c),从这里就可以看出8032
flash上的分区分布。整理如下图:

|