uboot使用
uboot控制檯,倒計時
命令: 調試,操做一些硬件linux
setenv printenv saveenv
nand erase
nand write
tftp
20008000 zImage
help
: uboot能夠提供哪些命令
setenv
== set
== sete
== seten
環境變量: 爲命令提供參數
serverip : tftp命令提供tftp服務器的地址
ipaddr : tftp命令提供tftp客戶端(開發板)的地址shell
兩個環境變量
uboot: 下載內核,並啓動內核
bootcmd: 倒計時結束後,uboot應該自動作什麼事情vim
set bootcmd tftp
20008000 zImage \; bootm
20008000
set serverip
192.
168.
7.
2
set ipaddr
192.
168.
7.
6
set ethaddr 00
:
22
:
23
:
24
:
25
:ee
倒計時結束的時候,uboot會執行bootcmd中的內容:
tftp 20008000 zImage ; bootm 20008000api
從tftp服務器(serverip)中將zImage文件(/tftpboot/)下載到開發板(ipaddr)中內存的20008000服務器
set bootcmd tftp 20008000 zImage ; bootm 20008000網絡
bootargs: 負責告訴內核文件系統在哪裏(uboot傳遞給內核, 內核要用)架構
set bootargs init
=
/linuxrc console
=ttySAC0,
115200 root
=
/dev
/nfs nfsroot
=
192.
168.
7.
2
:
/opt
/filesystem ip
=
192.
168.
7.
6
root
=xxxx
: 根文件系統目錄在哪裏
/dev
/nfs
: 根文件系統目錄在網絡的遠端
nfsroot
=xxxx
: 根文件系統目錄在哪臺機器的哪一個文件路徑
nfsroot
=
192.
168.
7.
2
:
/opt
/filesystem
ip
=
192.
168.
7.
6
: 系統登陸的時候,靜態分配一個ip
若是root
=
/dev
/nfs
root
=
/dev
/nfs
+ nfsroot
=xxxx
+ip
=xx
若是root
=
/dev
/mtdblock2(文件系統製做的時候會講)
root
=
/dev
/mtdblock2
+ rootfstype
=cramfs
console
=ttySAC0,
115200
: 內核啓動過程當中,調試信息往哪裏輸出,printk
init
=
/linuxrc
: 指定第一個init進程的可執行代碼文件
/opt
/filesystem
==
> host
:
/etc
/exports
sudo vim /etc/exports
/opt
/filesystem
*(subtree_check,rw,no_root_squash,async)
/opt
/fs100
/rootfs
*(subtree_check,rw,no_root_squash,async)
啓動內核:go/bootm
官方的ubootapp
zImage
:
go
set bootcmd tftp
20008000 zImage \; go
20008000
uImage
: bootm(下載地址,不能是
20008000)
set bootcmd tftp
20800000 uImage \; bootm
20800000
下載地址的選用
:
go
==
> 能夠是任何地址
bootm
==
>
20008000
+zImage的大小以上
==
>
20800000
綜合用法:
set bootcmd tftp
20800000 zImage \; go
20800000
set bootcmd tftp
20800000 uImage \; bootm
20800000
uboot1.
3.
4
:
zImage
/uImage
==
>bootm
set bootcmd tftp
20800000 uImage \; bootm
20800000
uboot的鏈接腳本
所在路徑:cpu/arm_cortexa8/u-boot.ldsasync
OUTPUT_FORMAT(
"elf32-littlearm",
"elf32-littlearm",
"elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
// 入口函數
SECTIONS
{
.
= 0x00000000;
// 當前的起始位置0x0
.
= ALIGN(
4);
.text(目標文件)
:
{
cpu
/arm_cortexa8
/start.o (.text)
// 第一個文件的.text
*(.text)
}
.
= ALIGN(
4);
// 當前位置四字節對齊
.rodata
: {
*(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata
*))) }
.
= ALIGN(
4);
.data
: {
*(.data) }
.
= ALIGN(
4);
.got
: {
*(.got) }
__u_boot_cmd_start
= .;
// 用__u_boot_cmd_start記錄當前的位置, 代碼會用到,全局的
.u_boot_cmd
: {
*(.u_boot_cmd) }
// 段數據
__u_boot_cmd_end
= .;
// 結束位置
.
= ALIGN(
4);
__bss_start
= .;
.bss
: {
*(.bss) }
_end
= .;
}
鏈接的基地址:
-Ttext 0x34800000==>board/samsung/smdkc100/config.mk
TEXT_BASE = 0x34800000
1,TEXT_BASE指定uboot的鏈接的起始位置
2,指定uboot重定位的位置(能夠改爲0x2ff00000)ide
uboot配置的詳細說明
make smdkc100_config
vim Makefile
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
MKCONFIG
:
= $(SRCTREE)
/mkconfig
== .
/mkconfig shell腳本(可執行程序)
smdkc100_config
: unconfig
@$(MKCONFIG) $(@
:_config
=) arm arm_cortexa8 smdkc100 samsung s5pc1xx
.
/mkconfig smdkc100 arm arm_cortexa8 smdkc100 samsung s5pc1xx
執行一個腳本: 傳遞了6個參數(控制源碼的編譯)
arm
: 架構
==
> lib_arm
smdkc100
: include
/configs
/smdkc100.h
/
/ 開發板全部的宏的配置
arm_cortexa8
: arm名
==
> cpu
/arm_cortexa8
smdkc100 samsung
: 開發板名
==
> board
/samsung
/smdkc100
s5pc1xx :cpu
==
>cpu
/arm_cortexa8
/s5pc1xx
$(@
:_config
=)
: $@
:_config
=
==
>smdkc100_config
:_config
=
/
/ _config替換成空,去掉
$(@
:_config
=xxx)
==
=
>smdkc100xxx
uboot第一階段啓動流程

1,創建異常向量表
:
_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
:
/*
* set the cpu to SVC32 mode, disable F, I
*/
mrs r0, cpsr
bic r0, r0, #0x1f
orr r0, r0, #0xd3
msr cpsr,r0
bl cpu_init_crit
|
/*
* Invalidate L1 I/D
*/
mov r0, #
0 @ set up
for MCR
mcr p15,
0, r0, c8, c7,
0 @ invalidate TLBs
mcr p15,
0, r0, c7, c5,
0 @ invalidate icache
/*
* disable MMU stuff and caches
*/
mrc p15,
0, r0, c1, c0,
0
bic r0, r0, #0x00002000 @ clear bits
13 (
--V
-)
bic r0, r0, #0x00000007 @ clear bits
2
:
0 (
-CAM)
orr r0, r0, #0x00000002 @ set bit
1 (
--A
-) Align
orr r0, r0, #0x00000800 @ set bit
12 (Z
--
-) BTB
mcr p15,
0, r0, c1, c0,
0
bl lowlevel_init
//lowlevel_init.S (board\samsung\smdkc100):lowlevel_init:
|
/* Disable Watchdog */
ldr r0,
=S5PC100_WATCHDOG_BASE @0xEA200000
orr r0, r0, #0x0
str r5, [r0]
/* setting SRAM */
ldr r0,
=S5PC100_SROMC_BASE
ldr r1,
=0x9
str r1, [r0]
/* S5PC100 has 3 groups of interrupt sources */
ldr r0,
=S5PC100_VIC0_BASE @0xE4000000
ldr r1,
=S5PC100_VIC1_BASE @0xE4000000
ldr r2,
=S5PC100_VIC2_BASE @0xE4000000
/* Disable all interrupts (VIC0, VIC1 and VIC2) */
mvn r3, #0x0
str r3, [r0, #0x14] @INTENCLEAR
str r3, [r1, #0x14] @INTENCLEAR
str r3, [r2, #0x14] @INTENCLEAR
/* Set all interrupts as IRQ */
str r5, [r0, #0xc] @INTSELECT
str r5, [r1, #0xc] @INTSELECT
str r5, [r2, #0xc] @INTSELECT
/* Pending Interrupt Clear */
str r5, [r0, #0xf00] @INTADDRESS
str r5, [r1, #0xf00] @INTADDRESS
str r5, [r2, #0xf00] @INTADDRESS
bl uart_asm_init
// 只是設置了gpio的功能,波特率的設置在第二階段
#
if
1
// 改動的部分
/* init system clock */
bl system_clock_init
// 基本上沒太大問題
bl mem_ctrl_asm_init
//mem_setup.S board\samsung\Smdkc100
// 內存的初始化比較複雜, 原廠會提供(1.3.4)
// 向FAE要
// 這部分代碼運行有問題
1,mem_ctrl_asm_init
2,mem_setup.S須要被編譯
<
==
=board\samsung\Smdkc100\Makefile
3,內存初始化代碼應該在前
16k (反彙編)
修改cpu
/arm_cotexa8
/u
-boot.lds
棧的初始化:
/* Set up the stack */
stack_setup:
ldr r0, _TEXT_BASE @ upper
128 KiB
: relocated uboot
sub r0, r0, #CONFIG_SYS_MALLOC_LEN @ malloc area
sub r0, r0, #CONFIG_SYS_GBL_DATA_SIZE @ bdinfo
#
ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ
+ CONFIG_STACKSIZE_FIQ)
#
endif
sub sp, r0, #
12 @ leave
3 words
for abort
-stack
and sp, sp, #
~
7 @
8 byte alinged
for (ldr
/str)d
uboot代碼的自我拷貝:
/* nand src offset : 0x0*/
mov r0, #0x0
/* ddr dst addr : 0x2ff00000*/
ldr r1,
=0x2ff00000
/*size*/
ldr r2,
=0x40000
bl copy2ddr
ddr的地址(重定位的目標地址)
: 和uboot的連接的基地址要同樣
board
/samsung
/smdkc100
/config.mk
TEXT_BASE
=xxxx
清bss端
/* Clear BSS (if any). Is below tx (watch load addr - need space) */
clear_bss:
ldr r0, _bss_start @ find start of bss segment
ldr r1, _bss_end @ stop here
mov r2, #0x00000000 @ clear value
clbss_l:
str r2, [r0] @ clear BSS location
cmp r0, r1 @ are we at the end yet
add r0, r0, #4 @ increment clear index pointer
bne clbss_l @ keep clearing till at end
跳轉到c階段
ldr pc, _start_armboot @ jump to C code
_start_armboot: .word start_armboot
_start_armboot: .word start_armboot
//start_armboot它的值是在編譯的時候就已經肯定:0x2ff00000+offset==> 0x2ff00980
arm: 基本全部的指令都是位置無關(指令在哪裏執行均可以)
有些代碼是位置有關: ldr pc, _start_armboot (pc跳轉的目標地址_start_armboot(0x2ff00980),和特定的位置相關)
ldr自己這條指令是位置無關,整個ldr pc, _start_armboot==>成爲一個位置相關的指令
連接地址: 連接器爲全部的指令作的排序, 確定有有個基地址: 基地址+該指令的偏移量
運行地址: 指令實際加載的地址,運行時,指令存放地址
物理地址: 和硬件相關,數據手冊中的地址都是物理地址, 硬件工程師爲設備設定的值
虛擬地址: 通常和mmu相關
思路:
1,支持一種啓動模式nand啓動
a, 時鐘和內存的初始化
1,mem_setup.S 被編譯
b, 完成自拷貝的實現
nand_ops.c(讀操做)
nand(0x0) --> ddr(TEXT_BASE)
board/samsung/smdkc100/config.mk
c,第一階段的代碼必須所有在前16k
u-boot.lds
d, 熟悉一下第一階段的啓動流程代碼
uboot第二階段代碼
lib_arm/Board.c
void start_armboot (void)
爲何老是去看smkdc100.h
#
include
<common.h
>
|
#
include
<config.h
>
|
#
define CONFIG_BOARDDIR board
/samsung
/smdkc100
#
include
<config_defaults.h
>
#
include
<configs
/smdkc100.h
>
#
include
<
asm
/config.h
>
先看主線流程
// 設置gd指針指向特定位置
gd
= (gd_t
*)(_armboot_start
- CONFIG_SYS_MALLOC_LEN
-
sizeof(gd_t));
// gd指針指向的空間,清零
memset ((
void
*)gd,
0,
sizeof (gd_t));
gd
-
>bd
= (bd_t
*)((
char
*)gd
-
sizeof(bd_t));
memset (gd
-
>bd,
0,
sizeof (bd_t));
// 初始化序列
for (init_fnc_ptr
= init_sequence;
*init_fnc_ptr;
++init_fnc_ptr) {
if ((
*init_fnc_ptr)()
!=
0) {
hang ();
}
}
// 堆的初始化
/* armboot_start is defined in the board-specific linker script */
mem_malloc_init (_armboot_start
- CONFIG_SYS_MALLOC_LEN,
CONFIG_SYS_MALLOC_LEN);
#
if
defined(CONFIG_CMD_NAND)
// CONFIG_CMD_NAND沒有定義
puts (
"NAND: ");
nand_init();
/* go init the NAND */
#
endif
// 環境變量的重定位
env_relocate ();
// 串口的初始化
serial_initialize();
// 無需關心
/* IP Address */
gd
-
>bd
-
>bi_ip_addr
= getenv_IPaddr (
"ipaddr");
stdio_init ();
/* get the devices list going. */
jumptable_init ();
console_init_r ();
// 中斷的使能
/* enable exceptions */
enable_interrupts ();
/* Initialize from environment */
if ((s
= getenv (
"loadaddr"))
!= NULL) {
load_addr
= simple_strtoul (s, NULL,
16);
}
if ((s
= getenv (
"bootfile"))
!= NULL) {
copy_filename (BootFile, s,
sizeof (BootFile));
}
// 網卡的初始化
eth_initialize(gd
-
>bd);
//死循環
for (;;) {
main_loop ();
}
模塊的方式
for (init_fnc_ptr
= init_sequence;
*init_fnc_ptr;
++init_fnc_ptr) {
if ((
*init_fnc_ptr)()
!=
0) {
hang ();
}
}
arch_cpu_init,
board_init,
// smdkc100開發板的總體的初始化
timer_init,
// 定時器的初始化, timer4==>倒計時的間隔時間,產生一個10ms的間隔
env_init,
// 環境變量的初步初始化 /* initialize environment */
init_baudrate,
// 波特率的設置 /* initialze baudrate settings */
serial_init,
// 串口的初始化 /* serial communications setup */
// 分水嶺, 纔可以使用printf去打印調試信息
console_init_f,
/* stage 1 init of console */
display_banner,
/* say that we are here */
print_cpuinfo,
/* display cpu info (and speed) */
checkboard,
/* display board info */
dram_init,
/* configure available RAM banks */
display_dram_config
環境變量處理:
COBJS
-$(CONFIG_ENV_IS_IN_NAND)
+= env_nand.o
環境變量的保存到哪一個地方
: CONFIG_ENV_IS_IN_NAND
env_init
|
gd
-
>env_addr
= (ulong)
&default_environment[
0];
//gd->env_addr指向默認的環境變量
gd
-
>env_valid
=
1;
env_relocate ();
|
//分配空間,128k
env_ptr
= (env_t
*)malloc (CONFIG_ENV_SIZE);
env_relocate_spec ();
|
// 從nand中0x40000讀取數據到malloc區域
ret
= readenv(CONFIG_ENV_OFFSET, (u_char
*) env_ptr);
if (ret)
//若是讀取失敗,就使用默認的環境變量
return use_default();
//讀取數據成功,此時還要crc校驗一下,
if (crc32(
0, env_ptr
-
>data, ENV_SIZE)
!= env_ptr
-
>crc)
//若是校驗失敗,仍然使用默認的環境變量
return use_default();
|
puts (
"*** Warning - bad CRC or NAND, using default environment\n\n");
memset(env_ptr,
0,
sizeof(env_t));
// 使用默認的環境變量
memcpy(env_ptr
-
>data, default_environment,
sizeof(default_environment));
//CONFIG_ENV_OFFSET是能夠控制env保存到nand中特定的位置
// 0x40000
readenv(CONFIG_ENV_OFFSET, (u_char
*) env_ptr);
|
// 0x40000 塊大小 , malloc區域
char_ptr
=
&buf[amount_loaded];
nand_read(
&nand_info[
0], offset,
&len, char_ptr)
|
// mtd的架構
info
-
>read(info, ofs,
*len, (size_t
*)len, buf);
本身設定環境變量
:
smdkc100.h
#
define CONFIG_SERVERIP
192.
168.
7.
2
#
define CONFIG_IPADDR
192.
168.
7.
6
#
define CONFIG_ETHADDR 00
:
23
:
24
:
25
:
26
:
27
#
define CONFIG_BOOTCOMMAND
"tftp 20800000 zImage35 \; go 20800000"
#
define CONFIG_BOOTARGS
"root=/de/nfs nfsroot=192.168.7.2:/opt/filesystem ip=192.168.7.6 console=ttySAC0,115200 init=/linuxrc"
插曲:函數指針
1,聲明定義
int
* fun(
int a,
int b);
int (
*fun)(
int a,
int b);
2,初始化
int add(
int a,
int b)
{
return a
+b;
}
int sub(
int a,
int b)
{
return a
-b;
}
//fun = add;
fun
= sub;
3,調用
fun(
3,
4);
4,做用
a,產生api
b,用於抽象分層
struct stud{
int age;
int (
*func)(
int a,
int b);
}
app
查詢
: a的名字
printf(
"age = %d\n", p
-
>age);
p
-
>func(
3,
4);
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
=
(核心層)鏈表
:
struct stud
*p; (全局)
p
= 鏈表頭;
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
==
=
(特定數據層)
struct stud a;
a.age
=
30000;
a.func
= add;
struct stud b;
b.age
=
3;
b.func
= sub;
nandflash的初始化;
void
start_armboot (
void)
|
nand_init();
|Nand.c drivers\mtd\Nand
2677
2010
-
4
-
1
nand_init_chip(
&nand_info[i],
&nand_chip[i], base_address[i]);
|(
struct mtd_info
*mtd,
struct nand_chip
*nand,ulong base_addr)
mtd
-
>priv
= nand;
board_nand_init(nand)
// 初始化nand_chip對象
|
nand
-
>IO_ADDR_R
= (
void __iomem
*)NFDATA;
nand
-
>IO_ADDR_W
= (
void __iomem
*)NFDATA;
nand
-
>cmd_ctrl
= s3c_nand_hwcontrol;
nand
-
>dev_ready
= s3c_nand_device_ready;
nand
-
>select_chip
= s3c_nand_select_chip;
nand
-
>options
=
0;
nand_scan(mtd, maxchips)
// 初始化struct nand_info
readenv
|
nand_read(
info
-
>read()
// 誰給這個read函數指針初始化
-
>read
= xxx
初始化部分:
nand_scan
|
nand_scan_tail(mtd);
|
//在這個地方給初始化了
mtd
-
>read
= nand_read;
// Nand_base.c drivers\mtd\Nand 81953 2010-4-1
|
struct nand_chip
*chip
= mtd
-
>priv;
nand_do_read_ops(mtd, from,
&chip
-
>ops);
|
chip
-
>select_chip(mtd, chipnr);
//select_chip在哪裏初始化
nand_scan
|
nand_scan_ident(mtd, maxchips);
|
// 片選在這個初始化了
chip
-
>select_chip
= nand_select_chip;
|
//chip實際就是struct nand_chip,
chip
-
>cmd_ctrl(mtd, NAND_CMD_NONE,
0
| NAND_CTRL_CHANGE);
|
s3c_nand_hwcontrol;
board_nand_init(nand)
// 初始化nand_chip對象,
|
nand
-
>IO_ADDR_R
= (
void __iomem
*)NFDATA;
nand
-
>IO_ADDR_W
= (
void __iomem
*)NFDATA;
nand
-
>cmd_ctrl
= s3c_nand_hwcontrol;
nand
-
>dev_ready
= s3c_nand_device_ready;
nand
-
>select_chip
= s3c_nand_select_chip;
nand
-
>options
=
0;
uboot命令處理的邏輯過程
struct
cmd_tbl_s {
char
*name;
/* Command Name */
int maxargs;
/* maximum number of arguments */
int repeatable;
/* autorepeat allowed? */
/* Implementation function */
int (
*cmd)(
struct cmd_tbl_s
*,
int,
int,
char
*[]);
char
*usage;
/* Usage message (short) */
char
*help;
/* Help message (long) */
};
typedef
struct cmd_tbl_s cmd_tbl_t;
#
define
U_BOOT_CMD(name,maxargs,rep,cmd,usage,help) \
cmd_tbl_t __u_boot_cmd_##name Struct_Section
= {#name, maxargs, rep, cmd, usage, help}
#
define Struct_Section __attribute__ ((unused,section (
".u_boot_cmd")))
U_BOOT_CMD(
tftpboot,
3,
1, do_tftpb,
"boot image via network using TFTP protocol",
"[loadAddress] [[hostIPaddr:]bootfilename]"
);
==
=
>展開
:
類型 變量名 設置屬性
struct cmd_tbl_s __u_boot_cmd_tftpboot __attribute__ ((unused,section (
".u_boot_cmd")))
={
.name
=
"tftpboot",
.maxargs
=
3,
.repeatable
=
1,
.cmd
= do_tftpb,
.usage
=
"boot image via network using TFTP protocol",
.help
=
"[loadAddress] [[hostIPaddr:]bootfilename]"
}
==
=
>
在uboot中新增一條命令
:
common/cmd_hello.c
#
include
<common.h
>
#
include
<command.h
>
int
do_mycmd(cmd_tbl_t
*cmdtp,
int flag,
int argc,
char
*argv[])
{
printf(
"in do_mycmd for uboot cmd test\n");
return
0;
}
U_BOOT_CMD(
mycmd,
3,
1, do_mycmd,
"this is a uboot cmd test",
"mycmd : no args"
);
common/Makefile
COBJS
-$(CONFIG_CMD_HELLO)
+= cmd_hello.o
smdkc100.h
#
define CONFIG_CMD_HELLO
1
uboot命令解析過程

mainloop:(通常不須要去修改)
s
= getenv (
"bootdelay");
//獲取環境變量的值(字符串)
bootdelay
= s
? (
int)simple_strtol(s, NULL,
10)
: CONFIG_BOOTDELAY;
s
= getenv (
"bootcmd");
//獲取bootcmd中值==>"tftp 20008000 zImage ; go 20008000"
if (bootdelay
>
=
0
&& s
&&
!abortboot (bootdelay))
// 倒計時
run_command (s,
0);
|
分析字符串中命令
: 命令名 參數tftp
20008000 zImage
argc
=
>
3
argv
==argv[
0]
==
"tftp"
argv[
1]
==
"20008000"
argv[
2]
==
"zImage"
argc
= parse_line (finaltoken, argv);
cmd_tbl_t
*cmdtp
= find_cmd(argv[
0]);
|
find_cmd_tbl(cmd,
&__u_boot_cmd_start, len);
|
// cmdtp爲指針,執行.u_boot_cmd段的起始位置
for (cmdtp
= table; cmdtp
!= table
+ table_len;cmdtp
++)
if (strncmp (cmd, cmdtp
-
>name, len)
return cmdtp;
(cmdtp
-
>cmd) (cmdtp, flag, argc, argv)
// 執行命令的處理函數
倒計時被打斷的時候
:
for (;;) {
len
= readline (CONFIG_SYS_PROMPT);
rc
= run_command (lastcommand, flag);
掌握:
1, 在uboot添加命令
2, 已知的命令對應的處理函數
nand 命令==> cmd_nand.c
do_nand
dm9000網卡:
void start_armboot (
void)
|
eth_initialize(gd
-
>bd);
// 沒有調用全部網卡的init方法
|
dm9000_initialize(bis)
// 本身添加,將dm9000的對象初始化,而且設置mac地址,加入鏈表
eth_getenv_enetaddr_by_index(eth_number, env_enetaddr);
//從環境變量中獲取,某個網卡的mac地址, mac從軟件上設定的
// mac保存在env_enetaddr
eth_init(gd
-
>bd);
// Eth.c Net 11013 2013-9-10
// 意味着鏈表中多有的節點都會執行其中的init方法
|
while循環
:
eth_current
-
>init(eth_current,bis)
// 執行當前的節點的init方法
eth_try_another(
0);
|
eth_current
= eth_current
-
>next;
1,dm9000
==
>鏈表中
dm9000_initialize(bis) ;
2,執行dm9000的init方法
eth_init(gd
-
>bd);
COBJS
-$(CONFIG_DRIVER_DM9000)
+= dm9000x.o
struct eth_device {
char name[NAMESIZE];
// 網卡名字
unsigned
char enetaddr[
6];
//網卡mac地址
int iobase;
//網卡的物理地址
int state;
//網卡狀態
int (
*init) (
struct eth_device
*, bd_t
*);
// 初始化方法
int (
*send) (
struct eth_device
*,
volatile
void
* packet,
int length);
// 發送
int (
*recv) (
struct eth_device
*);
//接收
void (
*halt) (
struct eth_device
*);
// 終止
struct eth_device
*next;
void
*priv;
};
int dm9000_initialize(bd_t
*bis)
{
struct eth_device
*dev
=
&(dm9000_info.netdev);
/* Load MAC address from EEPROM */
dm9000_get_enetaddr(dev);
dev
-
>init
= dm9000_init;
dev
-
>halt
= dm9000_halt;
dev
-
>send
= dm9000_send;
dev
-
>recv
= dm9000_rx;
sprintf(dev
-
>name,
"dm9000");
eth_register(dev);
// 將dm9000節點放到鏈表中
return
0;
}
uboot是如何啓動內核
1, 在0x20000100去存放內存的信息和bootargs的內容
2, 將r1=1826,告訴內核
bootm
--
>uImage
tftp
20800000 uImage \; bootm
20800000
gd
-
>bd
-
>bi_arch_number
= MACH_TYPE_SMDKC100;
// 1826
gd
-
>bd
-
>bi_boot_params
= PHYS_SDRAM_1
+ 0x100;
// 0x20000000+0x100
bootm
==
>do_bootm
|
將zImage拷貝到0x20008000
boot_fn
= boot_os[images.os.os];
|
do_bootm_linux
//Bootm.c (lib_arm):int do_bootm_linux
|
//gd->bd->bi_arch_number = MACH_TYPE_SMDKC100; 1826
bd_t
*bd
= gd
-
>bd;
int machid
= bd
-
>bi_arch_number;
void (
*theKernel)(
int zero,
int arch, uint params);
char
*commandline
= getenv (
"bootargs");
theKernel
= (
void (
*)(
int,
int, uint))images
-
>ep;
// 0x20008000
setup_start_tag (bd);t
setup_memory_tags (bd);
setup_commandline_tag (bd, commandline);
setup_end_tag (bd);
theKernel (
0, machid, bd
-
>bi_boot_params);
全局的數據:gd
DECLARE_GLOBAL_DATA_PTR;
#
define DECLARE_GLOBAL_DATA_PTR
register
volatile gd_t
*gd
asm (
"r8")
某個.c中想使用gd變量
: 加上這句話
DECLARE_GLOBAL_DATA_PTR;
gd
-
>flags
|= GD_FLG_RELOC;
board_init
|
gd
-
>bd
-
>bi_arch_number
= MACH_TYPE_SMDKC100;
// 1826
gd
-
>bd
-
>bi_boot_params
= PHYS_SDRAM_1
+ 0x100;
// 0x20000000 + 0x100
env_init
|
gd
-
>env_addr
= (ulong)
&default_environment[
0];
gd
-
>env_valid
=
1;
init_baudrate
|
gd
-
>bd
-
>bi_baudrate
= gd
-
>baudrate
=
115200;
serial_init
==
>drivers
/serial
/serial_s5pc1xx.c
// 通常uboot對於串口的部分,都基本上是ok
int serial_init_dev(
const
int dev_index)
{
struct s5pc1xx_uart
*
const uart
= s5pc1xx_get_base_uart(dev_index);
/* reset and enable FIFOs, set triggers to the maximum */
writel(
0,
&uart
-
>ufcon);
writel(
0,
&uart
-
>umcon);
/* 8N1 */
writel(0x3,
&uart
-
>ulcon);
/* No interrupts, no DMA, pure polling */
writel(0x245,
&uart
-
>ucon);
serial_setbrg_dev(dev_index);
return
0;
}
gd
-
>have_console
=
1;
dram_init
:
gd
-
>bd
-
>bi_dram[
0].start
= PHYS_SDRAM_1;
//起始位置
gd
-
>bd
-
>bi_dram[
0].size
= get_ram_size((
long
*)PHYS_SDRAM_1,PHYS_SDRAM_1_SIZE);
// 計算內存大小
=
256
*
1024
*
1024
彙總:
gd
-
>bd
-
>bi_arch_number
= MACH_TYPE_SMDKC100;
// 1826, 機器id, uboot和內核達成的一個協議
gd
-
>bd
-
>bi_boot_params
= PHYS_SDRAM_1
+ 0x100;
// 0x20000000 + 0x100
gd
-
>bd
-
>bi_baudrate
= gd
-
>baudrate
=
115200;
gd
-
>bd
-
>bi_dram[
0].start
= PHYS_SDRAM_1;
gd
-
>bd
-
>bi_dram[
0].size
=
256
*
1024
*
1024;
gd
-
>have_console
=
1;
gd
-
>flags
|= GD_FLG_RELOC;
gd
-
>bd
-
>bi_ip_addr
= getenv_IPaddr (
"ipaddr");
串口的初始化
//串口的初始化, 將全部的串口設備作成對象 struct serial_device, 用鏈表鏈接起來
serial_initialize();
//將全部的外圍設備所有作成對象 struct stdio_dev, 若是想要研究uboot中有lcd,研究這塊
stdio_init ();
/* get the devices list going. */
// 跳轉表
jumptable_init ();
// 將stdin, out, err==> serial
console_init_r ();
/* fully init console as a device */
/* enable exceptions */
enable_interrupts ();
smdkc100全部平臺數據的註冊流程
static
int __init customize_machine(
void)
{
/* customizes platform devices, or adds new ones */
if (init_machine)
init_machine();
return
0;
}
arch_initcall(customize_machine);
smdkc100_machine_init
|
platform_add_devices(smdkc100_devices, ARRAY_SIZE(smdkc100_devices));
|
platform_device_register(devs[i]);
init
/main.c
start_kernel
|
printk(KERN_NOTICE
"%s", linux_banner);
setup_arch(
&command_line);
// 創建平臺相關的數據,會到0x200000100去uboot存放數據
|
mdesc
= setup_machine(machine_arch_type);
// 獲取machine描述
//struct machine_desc *mdesc===>mach-smdkc100.c==>MACHINE_START
mdesc
-
>boot_params;
//獲取0x20000100
tags
= phys_to_virt(mdesc
-
>boot_params);
parse_tags(tags);
// 獲取bootargs, from就在這裏初始化
strlcpy(boot_command_line, from, COMMAND_LINE_SIZE);
printk(KERN_NOTICE
"Kernel command line: %s\n", boot_command_line);
內核是如何去處理bootargs中的全部參數:
parse_args(
"Booting kernel", static_command_line, __start___param,__stop___param
- __start___param,
&unknown_bootoption);
用途
:
uboot想傳遞一個自定義的值給咱們內核,內核如何處理
:
set bootargs myval
=
56 init
=
/linuxrc console
=ttySAC0,
115200 root
=
/dev
/nfs nfsroot
=
192.
168.
7.
2
:
/opt
/filesystem ip
=
192.
168.
7.
6
在內核的任何地方
:
static
int __init parse_myval(
char
*str)
{
int val
= simple_strtoul(str, NULL,
10);
printk(
"myval = %d\n", val);
return
0;
}
__setup(
"myval=", parse_myval);
uboot上電完整內存使用

@成鵬致遠
(blogs:http://lcw.cnblogs.com)
(email:wwwlllll@126.com)
(qq:552158509)