系统移植第三天
为什么有全局数据结构?
帮助消除BSS段和DATA段,因为BSS段和DATA段必须放内存中才能运行,因为我们可能出现代码直接放在Norflash上面运行,这样的话我们就需要将BSS段与DATA段和代码段分开存放运行, 这样非常麻烦,所以我们要尽可能消除BSS段和data段,即:
不定义全局变量和静态局部变量,需要的全局数据放入全局数据区
bootm指令的作用
启动内核,在u-boot里面这个是标准内核启动命令##标示符连接#define MERGE(a, b) a##bMERGE(max, value)maxvalue#define str(a) #astr(go)"go"
源代码分析
启动内核 --> 拷贝到内存 --> u-boot自己先启动 --> 关闭中断切换到SVC模式
关闭MMU关闭cache
关闭看门狗
如果希望加快代码运行速度,初始化clk control(PLL)
初始化SDRAM
驱动串口
驱动nandflash(读)
自拷贝到SDRAM
给malloc函数、全局数据结构、中断异常程序的栈预留内存
.bss段清0
给动态内存分配、全局数据
设置中断异常程序栈
初始化软硬件模块
读取命令,解析执行
运行内核 --> 拷贝内核到内存(命令实现)
运行内核(传递内核参数,并且跳转到内核运行)
内核启动前提条件:
1. 关闭中断,进入SVC模式
2. 关闭MMU和icache
3. R0 0 非强制
4. R1 arch number(machine type id) 主板id
5. R2 内核参数指针(tags list) 非强制
6. 传递内核参数(内存位置由内核(BSP))
跳转到内核运行
cpu/arm_cortexa8/start.S(reset --->cpu_init_crit)
-->board/samsung/fsc100/lowlevel_init.S(lowlevel_init-->system_clock_init)
-->uart_asm_init
-->dma_init
-->nand_pin_mux
?-->board/samsung/fsc100/mem_setup.S(mem_ctrl_asm_init)
-->wakeup_reset
?-->board/samsung/fsc100/nand_cp.c(stack_setup)
-->copy_uboot_to_ram
-->board/samsung/fsc100/nand_cp.c(stack_setup)
-->lib_arm/board.c(start_armboot)
-->common/main.c(main_loop)
reset 复位异常启动的正常代码
cpu_init_crit 关闭MMU和cache
lowlevel_init 关闭看门狗、初始化SRAM接口、初始化中断控制器、初始化PLL
system_clock_init 初始化PLL
dma_init 初始化dma
nand_pin_mux 初始化nandflash的多功能管脚
nand_asm_init nandflash初始化
mem_ctrl_asm_init DDR控制器初始化
wakeup_reset 唤醒复位
stack_setup 栈初始化
start_armboot 软硬件初始化
main_loop 初始化及命令循环
启动代码注意事项
1.启动代码中的跳转一定要用相对跳转(B或BL)
看源代码
vi + ctags 查看编辑代码
1. 进入顶层目录,按F9新建索引文件(tags)
2. 查找定义:把光标移动到要查找的标示符,然后按ctrl + ]
3. 回退:按ctrl + o
sourceinside
建立工程,添加文件到工程
移植总结
1. 添加配置命令
在Makefile中,添加如下规则:
fsc100_config: unconfig
@$(MKCONFIG) $(@:_config=) arm arm_cortexa8 fsc100 samsung s5pc1xx
2. 添加主板源代码目录
1. 启动代码
soc内部设置驱动:PLL、看门狗、UART、nand(读).......
SDRAM初始化
2. 主板的初始化代码
board_init
设置主板ID(arch number id/mach type id)
内核启动参数位置
dram_init
内存配置
3. Makefile
$(LIB) 库名字
$(COBJS) C语言源代码编译出来的目标文件
$(SBOJS) 汇编语言代码编译出来的目标文件
$(START) 启动代码的目标文件(需要添加到顶层目录下的Makefile中的OBJS变量中)
启动代码放在到代码段的最前面,方法有两个:
1. 在链接脚本中把目标文件放在代码段的最前面
section .text :
{
start.o(.text)
board/samsung/fsc100/lowlevel_init.o(.text) 被链接到代码段的最前面
}
2. 在Makefile把目标文件放在代码段的最前面
1. 拷贝cpu目录下的Makefile到主板目录
2. 将启动代码的目标文件,放在START变量中
START = lowlevel_init.o
3. 将启动代码的目标文件添加到顶层目录的Makefile
OBJS += board/samsung/fsc100/lowlevel_init.o
4. config.mk(代码段起始地址)
3. 新建主板配置文件
include/configs/fsc100.h(拷贝smdkc100.h)
1. 内存基地址和大小
CONFIG_SYS_SDRAM_BASE
PHYS_SDRAM_1_SIZE
2. nandflash配置
3. ICACHE关闭
4. 命令提示符
CONFIG_SYS_PROMPT
5. 内核加载地址
CONFIG_SYS_LOAD_ADDR
注意:配置项到REAME
4. 修改交叉编译
CROSS_COMPILE ?= arm-cortex_a8-linux-gnueabi-
5. 启动代码
一般大部分代码相同,只有可能有部分硬件不同:SDRAM、flash、中断异常模式栈设置关闭中断切换到SVC模式关闭MMU关闭cache关闭看门狗如果希望加快代码运行速度,初始化clk control(PLL)初始化SDRAM驱动串口驱动nandflash(读)自拷贝到SDRAM给malloc函数、全局数据结构、中断异常程序的栈预留内存.bss段清0给动态内存分配、全局数据设置中断异常程序栈
6. 添加自己特有硬件初始化代码(一般不在这个时候做)
7. 移植需要的命令
tftp: tftp协议、UDP协议、ip协议、arp协议、以太网协议、网卡驱动
config_cmd_default.h
config_cmd_all.h
8. 内核启动
bootm(依赖于主板的初始化代码)
内核启动条件
[1] 必须在SVC模式下,并且关闭中断[2] 必须关闭icache[3] 必须关闭MMU[4] r0 = 0[5] r1 = Machine type id[6] 参数传递tag list传递 可以不用管r2 = tags list参数传递办法(与参数结构体传递办法不一样)参数结构体传递: 必须掌握1.参数结构放在内存里面(BSP指定位置)2.参数结构内必须放置:内存的页大小和页数量内核的字符串参数(root=, init=, console=)
u-boot移植步骤
[1] 添加主板配置规则
[2] 添加主板代码目录
board/samsung/fsc100拷贝开发板u-boot源码中对应的目录:smdkc100(芯片厂家提供)-->fsc100(自己的主板要用的), 然后在修改里面的代码:1.在主板的初始化函数(board_init)里面加入:gd->bd->bi_arch_number = machine type id; // 机器idgd->bd->bi_boot_params = BSP中指定的内核参数存放位置上面这两个参数是u-boot, bootm命令使用2.设置内存大小:gd->bd->bi_dram[0].start = 内存的起始位置gd->bd->bi_dram[0].size = 内存的大小上面这两个参数是u-boot, bootm命令使用
[3] 启动代码修改:
主要原因,可能存在下面差异:1. 内存的位置和大小不一样,导致u-boot运行位置可能不一样2. 程序存放的位置可能一样(芯片厂家把程序存储在norflash, 我们把程序存储在nandflash)
[4] 添加主板配置
include/configs/smdkc100.h --> include/configs/fsc100.hinclude/config_default_cmd.h进行修改,根据下面的命令移植来修改
[5] 移植命令
1. 命令实现(命令代码本身)2. 命令依赖的协议栈(网络、文件系统、磁盘分区、usb协议栈.....)3. 命令依赖的硬件的驱动
[6] 操作系统启动
99%情况不需要做任何更改,只用bootm命令实现即可