uboot_启动过程分析
uboot源码分析(分为两个阶段)
第一阶段:
.globl _start u-boot-1.1.6\cpu\arm920t\start.S
_start: b reset
reset: u-boot-1.1.6\cpu\arm920t\start.S
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
blne cpu_init_crit
stack_setup:
ldr r0, _TEXT_BASE /* upper 128 KiB: relocated uboot */
sub r0, r0, #CFG_MALLOC_LEN /* malloc area */
sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo */
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
relocate: /* relocate U-Boot to RAM */
bl CopyCode2Ram /* r0: source, r1: dest, r2: size */ u-boot-1.1.6\board\100ask24x0\boot_init.c
clear_bss:
SetLoadFlag:
ldr pc, _start_armboot
_start_armboot: .word start_armboot u-boot-1.1.6\lib_arm\board.c
cpu_init_crit: u-boot-1.1.6\cpu\arm920t\start.S
bl lowlevel_init u-boot-1.1.6\board\smdk2410\lowlevel_init.S
第二阶段:(进入命令行状态)
void start_armboot (void) u-boot-1.1.6\lib_arm\board.c
{
// init_fnc_t *init_sequence[] = {
// cpu_init, /* basic cpu dependent setup */
// board_init, /* basic board dependent setup */
// interrupt_init, /* set up exceptions */
// env_init, /* initialize environment */
// init_baudrate, /* initialze baudrate settings */
// serial_init, /* serial communications setup */
// console_init_f, /* stage 1 init of console */
// display_banner, /* say that we are here */
// #if defined(CONFIG_DISPLAY_CPUINFO)
// print_cpuinfo, /* display cpu info (and speed) */
// #endif
// #if defined(CONFIG_DISPLAY_BOARDINFO)
// checkboard, /* display board info */
// #endif
// dram_init, /* configure available RAM banks */
// display_dram_config,
// NULL,
// };
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
size = flash_init ();
env_relocate ();
cs8900_get_enetaddr (gd->bd->bi_enetaddr);
for (;;) {
main_loop (); u-boot-1.1.6\common\main.c
}
}
void main_loop (void)
{
s = getenv ("bootcmd");
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
printf("Booting Linux ...\n");
run_command (s, 0);
}
for (;;) {
strcpy (lastcommand, console_buffer);
rc = run_command (lastcommand, flag);
}
}
int run_command (const char *cmd, int flag) u-boot-1.1.6\common\main.c
{
process_macros (token, finaltoken);
if ((argc = parse_line (finaltoken, argv)) == 0) {
if ((cmdtp = find_cmd(argv[0])) == NULL) {
}
cmd_tbl_t *find_cmd (const char *cmd) u-boot-1.1.6\common\command.c
{
cmd_tbl_t *cmdtp_temp = &__u_boot_cmd_start; /*Init value */
for (cmdtp = &__u_boot_cmd_start;
cmdtp != &__u_boot_cmd_end;
cmdtp++) {
}
u-boot-1.1.6\board\smdk2410/u-boot.lds
__u_boot_cmd_start = .;
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
u-boot-1.1.6\include\command.h
#define Struct_Section __attribute__ ((unused,section (".u_boot_cmd")))
#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}
U_BOOT_CMD( //本质是定义结构体
help, CFG_MAXARGS, 1, do_help,
"help - print online help\n",
"[command ...]\n"
" - show help information (for 'command')\n"
"'help' prints online help for the monitor commands.\n\n"
"Without arguments, it prints a short usage message for all commands.\n\n"
"To get detailed help information for specific commands you can type\n"
"'help' with one or more command names as arguments.\n"
);
int do_help (cmd_tbl_t * cmdtp, int flag, int argc, char *argv[])
{
}
Uboot启动内核:
bootcmd命令值为:nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
从NAND的的kernel分区读出内核放到0x30007FC0(并不是固定地址,可随意指定,因为bootm时会根据ih_load去判断加载),并启动
分区名字kernel不重要,其代表 地址和长度
等效于:nand read.jffs2 0x30007FC0 0x00060000 0x00200000;bootm 0x30007FC0
void main_loop (void)
{
s = getenv ("bootcmd");
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
printf("Booting Linux ...\n");
run_command (s, 0);
}
......
}
#define MTDIDS_DEFAULT "nand0=nandflash0" u-boot-1.1.6\include\configs\100ask24x0.h
#define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k@0(bootloader)," \
"128k(params)," \
"2m(kernel)," \ //分区是在源码中写死的
"-(root)"
int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) u-boot-1.1.6\common\cmd_nand.c
{
/* read write */
if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) {
ret = nand_read_opts(nand, &opts);
ret = nand_write_opts(nand, &opts);
}
typedef struct image_header {
uint32_t ih_magic; /* Image Header Magic Number */
uint32_t ih_hcrc; /* Image Header CRC Checksum */
uint32_t ih_time; /* Image Creation Timestamp */
uint32_t ih_size; /* Image Data Size */
uint32_t ih_load; /* Data Load Address */ 重要:加载地址,可理解为运行时的地址
uint32_t ih_ep; /* Entry Point Address */ 重要:入口地址
uint32_t ih_dcrc; /* Image Data CRC Checksum */
uint8_t ih_os; /* Operating System */
uint8_t ih_arch; /* CPU architecture */
uint8_t ih_type; /* Image Type */
uint8_t ih_comp; /* Compression Type */
uint8_t ih_name[IH_NMLEN]; /* Image Name */
} image_header_t;
image_header_t header;
int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
image_header_t *hdr = &header; //uImage = 头部 + 真正内核; 0x30007FC0 + 64(头部) = 0x30008000(真正内核的地址)
memmove (&header, (char *)addr, sizeof(image_header_t));
if(ntohl(hdr->ih_load) == data) { //如果内核已在正确地址上,不需移动
printf (" XIP %s ... ", name);
} else {
memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); //将内核移到正确的地址
}
do_bootm_linux (cmdtp, flag, argc, argv, //启动
addr, len_ptr, verify);
}
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[], u-boot-1.1.6\lib_arm\armlinux.c
ulong addr, ulong *len_ptr, int verify)
{
char *commandline = getenv ("bootargs");
//设置启动参数,在某个地址(0x30000100),按某种格式(TAG),保存数据
#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
defined (CONFIG_CMDLINE_TAG) || \
defined (CONFIG_INITRD_TAG) || \
defined (CONFIG_SERIAL_TAG) || \
defined (CONFIG_REVISION_TAG) || \
defined (CONFIG_LCD) || \
defined (CONFIG_VFD)
setup_start_tag (bd); //必须
setup_serial_tag (¶ms);
setup_memory_tags (bd);
setup_commandline_tag (bd, commandline);
setup_end_tag (bd); //必须
//跳到入口地址,启动内核
theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep); //取得入口地址
theKernel (0, bd->bi_arch_number, bd->bi_boot_params); //启动内核, bi_arch_number 为机器ID, int board_init (void){gd->bd->bi_arch_number = MACH_TYPE_SMDK2410; } 机器
}
static void setup_start_tag (bd_t *bd)
{
params = (struct tag *) bd->bi_boot_params; // int board_init (void) {gd->bd->bi_boot_params = 0x30000100; }
params->hdr.tag = ATAG_CORE; //0x54410001
params->hdr.size = tag_size (tag_core);
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next (params);
}
static void setup_memory_tags (bd_t *bd)
{
for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
params->hdr.tag = ATAG_MEM; //0x54410002
params->hdr.size = tag_size (tag_mem32);
params->u.mem.start = bd->bi_dram[i].start; //dram_init()函数中指定
params->u.mem.size = bd->bi_dram[i].size;
params = tag_next (params);
}
}
static void setup_commandline_tag (bd_t *bd, char *commandline)
{
/* eat leading white space */
for (p = commandline; *p == ' '; p++);
/* skip non-existent command lines so the kernel will still
* use its default command line.
*/
if (*p == '\0')
return;
params->hdr.tag = ATAG_CMDLINE; //0x54410009
params->hdr.size =
(sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;
strcpy (params->u.cmdline.cmdline, p);
params = tag_next (params);
}
static void setup_end_tag (bd_t *bd)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}
参考:韦东山Linux教程
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通