ok6410-uboot的配置和编译过程分析

时间:2022-07-27 16:36:11

一、uboot的的配置和编译

1、配置:make smdk6410_config

SRCTREE             := $(CURDIR)

MKCONFIG   := $(SRCTREE)/mkconfig

 

smdk6410_config   :      unconfig

       @$(MKCONFIG) $(@:_config=) arm s3c64xx smdk6410 samsung s3c6410

      

 

mkconfig  smdk6410 arm s3c64xx smdk6410 samsung s3c6410

s0        s1       s2  s3       s4      s5       s6

生成如下两个文件:

include/config.mk include/config.h

建立两个软链接文件:

ln -s asm-arm asm

ln -s arch-smdk6410 asm-arm/arch

 

2make

   在编译到最后看到了如下一句:

   arm-linux-ld -Bstatic -T /home/uboot/u-boot-6410/board/samsung/smdk6410/u-boot.lds -Ttext 0xc7e00000 ........

   通过上述可知,uboot.bin的链接地址为:0xc7e00000(整个地址是在board/samsung/smdk6410/config.mk定义),链接脚本为:u-boot.lds

   注意:u-boot.lds中定义了个“.u_boot_cmd”段,地址范围从__u_boot_cmd_start__u_boot_cmd_end

  

二、uboot的源码分析:

       uboot重要的功能如下:

       1)关看门狗

       2)初始化时钟

       3)初始化SDRAM

       4)初始化flash

       5)初始化网卡、usb、串口等

       6)加载内核并且启动内核喂你好你在干麻耶

       u-boot.lds中可以看出“start.o”放在最前面,那么也就注定start.s是整个uboot第一个运行的文件,这样我们就可以从start.s开始分析

       uboot

      

       start.s做了如下的功能:

       1)进入设置为svc

       2)关看门狗

       3)屏蔽中断

       4)初始化

       5)设置stack

       6)时钟

       7)代码重定位,从nand flash sd ram

       8)bss

       9start_armboot

      

       在进入了start_armboot之后工作流程如下图:

ok6410-uboot的配置和编译过程分析

       

最后,从env变量中获取到bootcmd参数(nand read 0xc0008000 0x100000 0x500000;bootm 0xc0008000),执行到了” nand read 0xc0008000 0x100000 0x500000”命令,从nand flash 中将内核到内存中,之后就执行bootm 0xc0008000。最后将会调用如下函数:

do_bootm ->do_bootm_linux->theKernel

1do_bootm:从0x500000中读取UImage的头部,填充到一个全局变量header 中。结构定义为:

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;

其中我们关心的是“ih_load”和“ih_ep”两个成员,ih_load指定了内核应该在内存的地址,ih_ep指定了执行内核时的入口地址。

2、知道了内核的在内存的地址和内核的入口地址,我们就可以开始启动内核了,但是在启动内核之前,还需要一些信息(如: bootargs,内存的大小、串口的波特率等)告诉内核。这些信息的收集就由“do_bootm_linux”收集。将信息收集好后,怎么样告诉内核呢?很简单,就是按照双方约定内存地址中开辟一块内存,按照双方约定的格式存储就好了!存储的格式如下:

struct tag_header {
	u32 size;
	u32 tag;
};

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;
};

添加这些信息首先调用setup_start_tag (bd),添加完后调用setup_end_tag (bd)

 

那这内存地址是在哪里呢?我们定义一个gd全局变量,内存地址保存在gd->bd-> bi_boot_params 中,对gb赋值是在函数“start_armboot”!gd的结构体的定义如下:

typedef struct bd_info {
    int			bi_baudrate;	/* serial console baudrate */
    unsigned long	bi_ip_addr;	/* IP Address */
    unsigned char	bi_enetaddr[6]; /* Ethernet adress */
    struct environment_s	       *bi_env;
    ulong	        bi_arch_number;	/* unique id for this board */
    ulong	        bi_boot_params;	/* where this board expects params */
    struct				/* RAM configuration */
    {
	ulong start;
	ulong size;
    } 			bi_dram[CONFIG_NR_DRAM_BANKS];
#ifdef CONFIG_HAS_ETH1
    /* second onboard ethernet port */
    unsigned char   bi_enet1addr[6];
#endif
} bd_t

typedef	struct	global_data {
	bd_t		*bd;
	unsigned long	flags;
	unsigned long	baudrate;
	unsigned long	have_console;	/* serial_init() was called */
	unsigned long	reloc_off;	/* Relocation Offset */
	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
#if 0
	unsigned long	cpu_clk;	/* CPU clock in Hz!		*/
	unsigned long	bus_clk;
	unsigned long	ram_size;	/* RAM size */
	unsigned long	reset_status;	/* reset status register at boot */
#endif
	void		**jt;		/* jump table */
} gd_t;

3、有了上述信息和配置后我们就可以开始启动内核,调用

theKernel (0, bd->bi_arch_number, bd->bi_boot_params),之后我们的linux内核就开始工作了,uboot的使命就完成了!