下面是我对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和指针!
版权声明:本文为博主原创文章,未经博主允许不得转载。