uboot内核启动过程源码分析

来源:互联网 发布:多玩魔兽盒子mac版 编辑:程序博客网 时间:2024/05/30 04:16

下面是我对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 structglobal_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_tlegacy_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_corecore;
struct tag_mem32mem;
struct tag_videotextvideotext;
struct tag_ramdiskramdisk;
struct tag_initrdinitrd;
struct tag_serialnrserialnr;
struct tag_revisionrevision;
struct tag_videolfbvideolfb;
struct tag_cmdlinecmdline;


/*
* Acorn specific
*/
struct tag_acornacorn;


/*
* DC21285 specific
*/
struct tag_memclkmemclk;
} 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和指针!
原创粉丝点击