uboot移植

一、嵌入式linux系统的启动过程

加载 挂载 调用
uboot(bootloader) -------------> kernel(uImage/zImage)------------>rootfs文件系统 ------------------>自动调用应用程序
boot--->硬件启动及初始化 初始化linux内核的资源 设置linux的环境变量
loader--->加载linux的内核 初始化驱动程序 linux shell命令
init进程

应用程序及数据
============================================================================================================================

二、什么是uboot?
uboot---->通用的bootloader
通用:1、uboot支持多种架构的CPU
2、可以启动多种操作系统:linux、wince、vxworks
3、支持多种硬件的板子

bootloader:
1、boot:
1)CPU级初始化(BL1):ARM汇编编程, cache、MMU、clock、uart、nand、DDR2 SDRAM
2)板级初始化: C语言编程:USB、LCD、网卡、I2C
2、loader
将操作系统内核从nand flash拷贝到内存,然后给内核传递参数,并启动linux内核


============================================================================================================================
三、uboot的使用
1、uboot的帮助
GEC210 # ?
2、go
执行内存中二进制可执行文件:go 0x30000000
3、tftp
通过tftp下载文件:tftp 0x30000000 lcd.bin
4、loady
使用yumodem协议,向内存中下载一个二进制文件

5、bdinfo
查看硬件平台的信息
GEC210 # bdinfo
arch_number = 0x00000998 ----》uboot针对硬件平台的ID,该ID会传给内核,内核在启动过程中会将该ID与自身的ID做比较
env_t = 0x00000000
boot_params = 0x30000100 ----》uboot会传递启动参数给kernel,启动参数存放的地址
DRAM bank = 0x00000000 ---->内存的通道0
-> start = 0x30000000 ---->通道0内存的起始地址
-> size = 0x10000000 ---->通道0的内存大小(256MB)
DRAM bank = 0x00000001
-> start = 0x40000000
-> size = 0x10000000
ethaddr = 00:40:5C:26:0A:5B ---->MAC地址,MAC并不是写在网卡芯片中,而是在程序代码中的。
ip_addr = 192.168.1.224
baudrate = 115200 bps


思考:
GEC210平台,内存的地址范围:0x30000000~0x4FFFFFFF(512MB)

6、printenv
输出uboot的环境变量

GEC210 # printenv
bootargs=root=/dev/mtdblock4 rootfstype=yaffs2 init=/init console=ttySAC0,115200
baudrate=115200
ethaddr=00:40:5c:26:0a:5b
netmask=255.255.255.0
gatewayip=192.168.1.1
bootdelay=1
serverip=192.168.1.222
tftp=0x40000000 start.bin;go 0x40000000
bootcmd=nand read 0x30008000 0x600000 0x500000;bootm 0x30008000
ipaddr=192.168.1.224
stdin=seria

l
stdout=serial
stderr=serial
filesize=0

Environment size: 408/16380 bytes

1)bootcmd
启动命令,告诉uboot初始化结束后,自动做什么工作?(告诉boot去哪里加载内核并启动内核)
bootcmd=nand read 0x30008000 0x600000 0x500000;bootm 0x30008000
从nand flash的0x600000地址上读取0x500000(5MB)大小的内容(zImage)到0x30008000地址上。
从0x30008000地址上开始启动内核。

setenv bootcmd 'nand read 0x30008000 0x600000 0x500000; bootm 0x300088000'

思考:
setenv bootcmd 'tftp 0x40000000 start.bin; go 0x40000000'

setenv bootcmd 'tftp 0x30008000 zImage; bootm 0x30008000'


2)bootargs
启动参数--->告诉linux内核如何启动,去那里挂载rootfs。
bootargs=root=/dev/mtdblock4 rootfstype=yaffs2 init=/init console=ttySAC0,115200

root=/dev/mtdblock4 --->rootfs在哪里,nand flash的第4个分区
rootfstype=yaffs2 ---->rootfs的格式。yaffs-->小页的nand(page=512B),yaffs2--->大页的nand(2048、4096)
init=/sbin/init ---->init是linux系统启动的第一个进程,该进程需要用户指定,一般是启动shell命令的环境。
console=ttySAC0,115200 --->指定linux内核的控制器台。

setenv bootargs 'console=ttySAC0,115200 root=/dev/mtdblock4 rootfstype=yaffs2 init=/sbin/init'


7、reset


============================================================================================================================
四、通过uboot更新系统

1、设置IP
#setenv ipaddr 192.168.1.5
#setenv serverip 192.168.1.6
#setenv gatewayip 192.168.1.1
#saveenv

提示:
如果删除错误的配置
#setenv ipserver 192.168.1.5
#setenv ipserver

2、使用uboot去烧写新的uboot
#tftp 0x40000000 u-boot.bin
#nand erase 0x0 0x100000
#nand write 0x40000000 0x0 0x100000

3、使用uboot去烧写内核(zImage/uImage)
#tftp 0x40000000 zImage
#nand erase 0x600000 0x500000
#nand write 0x40000000 0x600000 0x500000

4、使用uboot去烧写rootfs
#tftp 0x40000000 rootfs.img
#nand erase 0xe00000 0xF200000
#nand write.yaffs 0x40000000 0xe00000 xxxx ---》tftp下载文件的大小。

提示:
如果想要擦除整个nand flash
#nand erase 0


============================================================================================================================
五、编译粤嵌发布的uboot源码

1、设置uboot运行平台ARCH和交叉工具链CORSS_COMPILE
# vi Makefile
ifeq ($(ARCH),arm)
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-

2、对uboot进行配置
让uboot源码编译出来的u-boot.bin可以运行在特定的平台上。在Makefile文件中有配置入口,没有每个配置入口对用一个硬件平台。
gec210_nand_config : unconfig
@$(MKCONFIG) $(@:_config=) arm s5pc11x gec210 samsung s5pc110
@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/gec210/config.mk

$ make gec210_nand_config
Configuring for gec210_nand board...

3、编译

#make

/usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-objcopy --gap-fill=0xff -O srec u-boot u-boot.srec
/usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-objcopy --gap-fill=0xff -O binary u-boot u-boot.bin
/usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-objdump -d u-boot > u-boot.dis

查看反汇编文件:

c3e00000 <_start-0x10>:
c3e00000: 00002000 .word 0x00002000
...

c3e00010 <_start>:
c3e00010: ea000013 b c3e00064
c3e00014: e59ff014 ldr pc, [pc, #20] ; c3e00030 <_undefined_instruction>
c3e00018: e59ff014 ldr pc, [pc, #20] ; c3e00034 <_software_interrupt>
c3e0001c: e59ff014 ldr pc, [pc, #20] ; c3e00038 <_prefetch_abort>
c3e00020: e59ff014 ldr pc, [pc, #20] ; c3e0003c <_data_abort>
c3e00024: e59ff014 ldr pc, [pc, #20] ; c3e00040 <_not_used>
c3e00028: e59ff014 ldr pc, [pc, #20] ; c3e00044 <_irq>
c3e0002c: e59ff014 ldr pc, [pc, #20] ; c3e00048 <_fiq>

链接地址 机器码 汇编指令 注释


4、生成u-boot.bin
将uboot.bin烧写到nand flash的0地址。

============================================================================================================================
六、uboot移植的源码来源
我们找到一个uboot源码,将该源码移植到我们特定的平台,让源码可以在我们的平台上正常工作。

来源:
1、uboot的官网
http://www.denx.de/wiki/U-Boot/WebHome
ftp://ftp.denx.de/pub/u-boot/

2、芯片的原厂或代理商


3、第三方(开发板、方案商)

目前:

SMDKV210(三星) ------> GEC210(GEC)
原则:两块板子最好是一个CPU。


思路:
分析两块板子硬件的差异,根据差异修改源代码。


============================================================================================================================
七、uboot源码的结构
1、基于CPU架构的源码lib_XXX
lib_arm/

2、uboot支持的CPU
cpu/s5pc11x/

3、uboot支持的板子
board/samsung/smdkc110/

4、公共的代码common
与硬件无关,一般是存放uboot的命令。

5、驱动的源代码
drivers/

6、文件系统的源码
fs/

7、include头文件
include/s5pc110.h
include/s5pc11x.h
include/configs/smdkv210single.h

提示:
在嵌入式平台中的数据类型
char ---- 8bits, %c, %d
short ---- 16bits
int ---- 32bits
long ---- 与CPU的字长一致

8、mkconfig
配置脚本文件

9、net
网络相关的代码。

10、sd_fusing
制作uboot启动卡的文档。


============================================================================================================================
八、编译基于SMDKV210平台的uboot源码
在uboot源码支持的现有平台中,smdkv210与GEC210最接近,所以我们要先编译以下基于SMDKV210平台的源码。

1、设置uboot运行平台ARCH和交叉工具链CORSS_COMPILE
# vi Makefile
ifeq ($(ARCH),arm

)
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-

2、对uboot进行配置
让uboot源码编译出来的u-boot.bin可以运行在特定的平台上。在Makefile文件中有配置入口,没有每个配置入口对用一个硬件平台。
$ make smdkv210single_config
Configuring for smdkv210single board...


3、编译
#make

生成u-boot.bin,不能在GEC210平台上运行的。


============================================================================================================================
九、uboot源码的配置过程(以smdkv210平台为例)

smdkv210single_config : unconfig
@$(MKCONFIG) $(@:_config=) arm s5pc11x smdkc110 samsung s5pc110
@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/smdkc110/config.mk


配置过程所做的三个工作。
1、unconfig
删除原来的配置。
unconfig:
@rm -f $(obj)include/config.h $(obj)include/config.mk \
$(obj)board/*/config.tmp $(obj)board/*/*/config.tmp \
$(obj)include/autoconf.mk $(obj)include/autoconf.mk.dep \
$(obj)board/$(VENDOR)/$(BOARD)/config.mk

'@'---》消除shell命令的“回显”

------------------------------------------------------------------------------------
2、@$(MKCONFIG) $(@:_config=) arm s5pc11x smdkc110 samsung s5pc110

@mkconfig smdkv210single arm s5pc11x smdkc110 samsung s5pc110

shell的参数: -----》与uboot的源码的结构必须一致
$1 ---》 smdkv210single
配置入口:include/configs/smdkv210single.h

$2 ---》 arm
CPU的架构:
ifeq ($(ARCH),arm)
CROSS_COMPILE = /usr/local/arm/arm-2009q3/bin/arm-none-linux-gnueabi-
lib_arm/

$3 ---》 s5pc11x
CPU的型号
cpu/s5pc11x/
include/s5pc11x.h

$4 ---》 smdkc110
板子的名字:
board/samsung/smdkc110/

$5 ---》 samsung
厂家的名字:
board/samsung

$6 ---》 s5pc110
SOC--->system on chip,片上系统:
include/s5pc110.h
cpu/s5pc11x/s5pc110


分析mkconfig文件:
$1 ---》 smdkv210single
$2 ---》 arm
$3 ---》 s5pc11x
$4 ---》 smdkc110

$5 ---》 samsung (可选参数)
$6 ---》 s5pc110 (可选参数)

小结:mkconfig的作用?
cd ./include
1)ln -s asm-arm asm

2)ln -s asm-arm/arch-s5pc110 asm-arm/arch

3) ln -s s5pc110.h regs.h

4) ln -s arch-s5pc11x asm-arm/arch

5) ln -s asm-arch/proc-armv asm-arch/proc

6)创建一个config.mk,并写入内容:
ARCH=arm
CPU=s5pc11x
BOARD=smdkc110
VENDOR=samsung
SOC=s5pc110

7)创建config.h头文件,并写入内容
#include

-----------------------------------------------------------------------------------------
3、@echo "TEXT_BASE = 0xc3e00000" > $(obj)board/samsung/smdkc110/config.mk


TEXT_BASE = 0xc3e00000
写入
board/samsung/smdkc110/config.mk


提示:什么是TEXT_BASE?
代码段的基地址,
0xc3e00000 ---->是一个虚拟地址,在uboot是使用了MMU(虚拟地址--->物理地址)

0xc3e00000 -----------> 0x33e000

00
MMU(查表)

是一个链接地址。


============================================================================================================================
十、uboot移植过程
linux底层代码的移植需要具备的素质:
1、了解底层的软件代码(uboot:汇编):语法、流程、架构、框架模型
2、会分析原理图

1、修改串口控制台
SMDKV210 --->serial3(UART2)
GEC210 --->serial1(UART0)

$vim include/configs/smdkv210single.h
将:
#define CONFIG_SERIAL3 1 /* we use UART2 on SMDKC110 */
修改为:
#define CONFIG_SERIAL1 1 /* we use UART0 on SMDKC110 */

---------------------------------------------------------------------------
2、移植DDR2内存
GEC210 ---》 ch0 : 16bis * 64M * 2 = 256MB
ch1 : 16bis * 64M * 2 = 256MB

SMDKV210 ---》ch0 : 8bits 128M * 4 = 512MB
---> ch0 : 8bits 128M * 4 = 512MB


修改:
#define MEMORY_BASE_ADDRESS 0x30000000
#define SDRAM_BANK_SIZE 0x10000000

define MEMORY_BASE_ADDRESS1 0x40000000
define PHYS_SDRAM_2 (MEMORY_BASE_ADDRESS1)

https://www.360docs.net/doc/d03263265.html,
#define DMC0_MEMCONFIG_0 0x30F00313 // MemConfig0

DMC0_MEMCONFIG_0
[31:24] --->AXI Base Address
0x30
[23:16] --->AXI Base Address Mask
0xF0

[15:12] --->Address Mapping Method (AXI to memory)
0x0 = Linear ({bank, row, column, width}),

[11:8] --->Number of Column Address Bits
0x3 = 10 bits

[7:4] --->Number of Row Address Bits
0x1 = 13 bits

[3:0] --->Number of Banks
0x3 = 8 banks
提示:
求DDR内存的大小:(地址总线、数据总线)

2^(行地址+列地址+bank地址)*数据总线 = 2^(13+10+3)*16bits = 2^26 * 16bits = 64M *16bits


注意:
初始化DDR2内存,是在C语言运行之前。内存的初始化是汇编实现。


---------------------------------------------------------------------------
3、移植网卡
1)DM9000的基地址:0x88000000
偏移量是:0x8

2)初始化SROM1的寄存器

static void dm9000_pre_init(void)
{
unsigned int tmp;
/* DM9000 on SROM BANK1, 16 bit */
SROM_BW_REG &= ~(0xf << 4);
SROM_BW_REG |= (0x1 << 4); //--->初始化寄存器1:SROM_BW
SROM_BC1_REG = ((0<<28)|(0<<24)|(5<<16)|(0<<12)|(0<<8)|(0<<4)|(0<<0)); //初始化寄存器1:SROM_BC1
/* Set MP01_1 as SROM_CSn[1] */
tmp = MP01CON_REG;
tmp &=~(0xf<<4);
tmp |=(2<<4);
MP01CON_REG = tmp;
}

4、屏蔽SRAM 初始化代码
SMDKV210 --->SRAM
GEC210 --->NC

5、屏蔽初始化PMIC
SMDKV210 --->PMIC(MAX8698)
GEC210 --->NC

6、屏蔽 nor flash 初始化代码
SMDKV210 --->PMIC(MAX8698)
GEC210 --->NC

7、修改uboot环境参数(可选)
1)主机名
2)网络配置
3)启动命令
4)启动参数


==========================================================================================================
十一、问题分


1、如何制作一个启动卡
S5PV210支持从sd启动,需要将uboot写入SD,使用SD卡作为启动卡。
1)windows
SD-Flasher.exe
2)SD-fusing
------------------------------------------------------------
2、移植过程中,只输出“OK”
“OK”是在汇编阶段输出的,还没有运行C语言。


3、成功的标志
1)串口输出正常
2)能加载linux内核 bootcmd
3)能设置环境变量可以设置,可以保存
4)通过bdinfo命令查看板子信息
5)可以使用tftp下载文件

注意:uboot默认没有启动logo。


4、



5、


注意:
uboot的编译不能在windows和linux的共享编译。
==========================================================================================================
十二、如何找到uboot的入口

board/samsung/smdkc110/u-boot.lds

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)

ENTRY(_start) //程序的入口,相当于main函数
SECTIONS
{
. = 0x00000000;

. = ALIGN(4); //4字节对齐
.text : //代码段
{
cpu/s5pc11x/start.o (.text) //第一个要链接的目标文件
//得到uboot的入口:cpu/s5pc11x/start.S中的_start入口

cpu/s5pc11x/s5pc110/cpu_init.o (.text)
board/samsung/smdkc110/lowlevel_init.o (.text)
cpu/s5pc11x/onenand_cp.o (.text)
cpu/s5pc11x/nand_cp.o (.text)
cpu/s5pc11x/movi.o (.text)
common/secure_boot.o (.text)
common/ace_sha1.o (.text)
cpu/s5pc11x/pmic.o (.text)
*(.text)
}

. = ALIGN(4);
.rodata : { *(.rodata) } //只读数据区

. = ALIGN(4); //可读写的数据区
.data : { *(.data) }

. = ALIGN(4);
.got : { *(.got) }

__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;

. = ALIGN(4);
.mmudata : { *(.mmudata) } //存放MMU的pagetable(虚拟地址和物理地址的关系及该地址访问属性)

. = ALIGN(4);
__bss_start = .; //未初始化的数据段
.bss : { *(.bss) }
_end = .;
}



==========================================================================================================
十三、uboot的执行流程

cpu/s5pc11x/start.S

1、异常中断向量表
.globl _start
_start: b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq

2、reset:
msr cpsr_c, #0xd3 @ I & F disable, Mode: 0x13 - SVC

bl disable_l2cache
bl set_l2cache_auxctrl_cycle
bl enable_l2cache

/*
* Invalidate L1 I/D
*/


/*
* disable MMU stuff and caches
*/
3、得到CPU启动方式
/* Read booting information */
ldr r0, =PRO_ID_BASE
ldr r1, [r0,#OMR_OFFSET]
bic r2, r1, #0xffffffc1

r2寄存器保存启动方式:nand、 nor、SD、串口、

/* NAND BOOT *

/
cmp r2, #0x0 @ 512B 4-cycle
moveq r3, #BOOT_NAND

cmp r2, #0x2 @ 2KB 5-cycle GEC210启动方式
moveq r3, #BOOT_NAND

cmp r2, #0x4 @ 4KB 5-cycle 8-bit ECC
moveq r3, #BOOT_NAND

cmp r2, #0x6 @ 4KB 5-cycle 16-bit ECC
moveq r3, #BOOT_NAND

cmp r2, #0x8 @ OneNAND Mux
moveq r3, #BOOT_ONENAND

/* SD/MMC BOOT */
cmp r2, #0xc
moveq r3, #BOOT_MMCSD

/* NOR BOOT */
cmp r2, #0x14
moveq r3, #BOOT_NOR

/* Uart BOOTONG failed */
cmp r2, #(0x1<<4)
moveq r3, #BOOT_SEC_DEV

ldr r0, =INF_REG_BASE
str r3, [r0, #INF_REG3_OFFSET] //存放启动方式


4、bl lowlevel_init--->初级初始化

/* check reset status */
如果是冷启动,则初始化内存

1) /* Disable Watchdog */
ldr r0, =ELFIN_WATCHDOG_BASE /* 0xE2700000 */
mov r1, #0
str r1, [r0]

2) /* init system clock */
bl system_clock_init

3) /* Memory initialize */
bl mem_ctrl_asm_init

4) /* for UART */
bl uart_asm_init //串口输出'O'

5) bl tzpc_init

6) /* Print 'K' */
ldr r0, =ELFIN_UART_CONSOLE_BASE
ldr r1, =0x4b4b4b4b
str r1, [r0, #UTXH_OFFSET]


5、nand_boot ---》从nand flash中,将uboot代码拷贝到内存中。
mov r0, #0x1000
bl copy_from_nand
b after_copy

1)copy_from_nand @
nandll_read_blocks(CFG_PHY_UBOOT_BASE, COPY_BL2_SIZE);

拷贝的目标地址:0x33e00000
拷贝的大小是512KB(uboot.bin <= 512KB)

2)after_copy

6、MMU的初始化

1)初始化MMU的页表基地址
/* Set the TTB register */
ldr r0, _mmu_table_base
ldr r1, =CFG_PHY_UBOOT_BASE
ldr r2, =0xfff00000
bic r0, r0, r2
orr r1, r0, r1
mcr p15, 0, r1, c2, c0, 0

2)打开MMU
/* Enable the MMU */
mmu_on:
mrc p15, 0, r0, c1, c0, 0
orr r0, r0, #1
mcr p15, 0, r0, c1, c0, 0


7、将BBS段初始化为0
clear_bss:
ldr r0, _bss_start /* find start of bss segment */
ldr r1, _bss_end /* stop here */
mov r2, #0x00000000 /* clear */

clbss_l:
str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
ble clbss_l



8、跳转到start_arm_boot (进入C环境)
ldr pc, _start_armboot

_start_armboot:
.word start_armboot

lib_arm/board.c

1、初始化两个结构体bd_t和gd_t

2、进入死循环

for (;;) {
main_loop ();
}
1)等待bootdelay时间减到0,就自动执行bootcmd = nand read 0x30008000 0x600000 0x500000; bootm 0x300088000
2)在bootdelay减到0之前控制台接收任意一个按键,就会进入uboot命令行,循环处理uboot命令。









相关文档
最新文档