uboot内核启动过程源码分析

下面是我对uboot如何启动内核的代码进行的分析

需要了解的数据结构:

bd 数据结构:

typedef struct bd_info {
    int bi_baudrate; /* serial console baudrate */
    unsigned long bi_ip_addr; /* IP Address */
    struct environment_s       *bi_env;
    unsigned long        bi_arch_number; /* unique id for this board */
    unsigned long        bi_boot_params; /* where this board expects params */
    struct /* RAM configuration */
    {
unsigned long start;
unsigned long size;
    }bi_dram[CONFIG_NR_DRAM_BANKS];
} bd_t;


gd的数据结构:
typedef struct global_data {
bd_t *bd;
unsigned long flags;
unsigned long baudrate;
unsigned long have_console; /* serial_init() was called */
unsigned long env_addr; /* Address  of Environment struct */
unsigned long env_valid; /* Checksum of Environment valid? */
unsigned long fb_base; /* base address of frame buffer */
#ifdef CONFIG_VFD
unsigned char vfd_type; /* display type */
#endif
#ifdef CONFIG_FSL_ESDHC
unsigned long sdhc_clk;
#endif
#if 0
unsigned long cpu_clk; /* CPU clock in Hz! */
unsigned long bus_clk;
phys_size_t ram_size; /* RAM size */
unsigned long reset_status; /* reset status register at boot */
#endif
void **jt; /* jump table */

} gd_t;


函数的入口,也就是分析开始的地方:

这里是do_bootm_linux()函数,先要进行一些初始化操作
bd_t *bd = gd->bd;  //重要的数据结构bd->得到gd中的bd数据结构
char *s;
int machid = bd->bi_arch_number;     //获得机器号码
void (*theKernel)(int zero, int arch, uint params);     //申明一个函数指针,注意观察结构


#ifdef CONFIG_CMDLINE_TAG                 
char *commandline = getenv ("bootargs");    //如果定义了命令参数
#endif


theKernel = (void (*)(int, int, uint))images->ep;  //其实这个函数就是指向内核的入口地址的,
//参数可见下面的结构体:
还需要了解的一个数据结构uImage给内核加的头:
typedef struct bootm_headers {
/*
* Legacy os image header, if it is a multi component image
* then boot_get_ramdisk() and get_fdt() will attempt to get
* data from second and third component accordingly.
*/
image_header_t *legacy_hdr_os; /* image header pointer */
image_header_t legacy_hdr_os_copy; /* header copy */
ulong legacy_hdr_valid;


#if defined(CONFIG_FIT)
const char *fit_uname_cfg; /* configuration node unit name */


void *fit_hdr_os; /* os FIT image header */
const char *fit_uname_os; /* os subimage node unit name */
int fit_noffset_os; /* os subimage node offset */


void *fit_hdr_rd; /* init ramdisk FIT image header */
const char *fit_uname_rd; /* init ramdisk subimage node unit name */
int fit_noffset_rd; /* init ramdisk subimage node offset */


void *fit_hdr_fdt; /* FDT blob FIT image header */
const char *fit_uname_fdt; /* FDT blob subimage node unit name */
int fit_noffset_fdt;/* FDT blob subimage node offset */
#endif


#ifndef USE_HOSTCC
image_info_t os; /* os image info */
ulong ep; /* entry point of OS */


ulong rd_start, rd_end;/* ramdisk start/end */


#ifdef CONFIG_OF_LIBFDT
char *ft_addr; /* flat dev tree address */
#endif
ulong ft_len; /* length of flat device tree */


ulong initrd_start;
ulong initrd_end;
ulong cmdline_start;
ulong cmdline_end;
bd_t *kbd;
#endif


int verify; /* getenv("verify")[0] != 'n' */


#define BOOTM_STATE_START (0x00000001)
#define BOOTM_STATE_LOADOS (0x00000002)
#define BOOTM_STATE_RAMDISK (0x00000004)
#define BOOTM_STATE_FDT (0x00000008)
#define BOOTM_STATE_OS_CMDLINE (0x00000010)
#define BOOTM_STATE_OS_BD_T (0x00000020)
#define BOOTM_STATE_OS_PREP (0x00000040)
#define BOOTM_STATE_OS_GO (0x00000080)
int state;


#ifdef CONFIG_LMB
struct lmb lmb; /* for memory mgmt */
#endif
} bootm_headers_t;
从上面的结构体中是可以看出来ep的作用的!


下面这个函数就是来设置起始参数的:跟踪
setup_start_tag (bd);
static void setup_start_tag (bd_t *bd)
{
params = (struct tag *) bd->bi_boot_params;     //获得参数的起始地址,并且转换成tag结构体类型


params->hdr.tag = ATAG_CORE;                    //初始化params->hdr->tag
params->hdr.size = tag_size (tag_core);         //初始化params->hdr->size


params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;


params = tag_next (params);
}




#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))


这里列出参数的结构体:
struct tag {
struct tag_header hdr;
union {
struct tag_core core;
struct tag_mem32 mem;
struct tag_videotext videotext;
struct tag_ramdisk ramdisk;
struct tag_initrd initrd;
struct tag_serialnr serialnr;
struct tag_revision revision;
struct tag_videolfb videolfb;
struct tag_cmdline cmdline;


/*
* Acorn specific
*/
struct tag_acorn acorn;


/*
* DC21285 specific
*/
struct tag_memclk memclk;
} u;


展开struct tag_header hdr;得到
struct tag_header {
u32 size;
u32 tag;
};

接下来就执到了setup_commandline_tag (bd, commandline)函数  //设置命令行参数,跟踪调试
我们观察一下这个宏:#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))
表示现在params结构体指向tag结构体后面的部分!
下面这个函数就是来设置命令后参数的:跟踪
setup_commandline_tag (bd, commandline);  //设置命令行参数,跟踪调试
static void setup_commandline_tag (bd_t *bd, char *commandline)
{
char *p;


if (!commandline)
return;


/* 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;
params->hdr.size = (sizeof (struct tag_header) + strlen (p) + 1 + 4) >> 2;



strcpy (params->u.cmdline.cmdline, p);


params = tag_next (params);
}只是简单的复制参数!
最后会通过一个函数指针调用,完成启动内核:
theKernel (0, machid, bd->bi_boot_params);           //真正的启动内核
大家肯定会有疑问:bd->bi_boot_params是在哪里设置的呢?
还记得void setup_start_tag (bd_t *bd)这个函数把,里面有一句:
params = (struct tag *) bd->bi_boot_params;
具体的请参考c和指针!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值