U-BootとLinuxカーネルのインタラクション

14300 ワード

U-BootとLinuxカーネルのインタラクション
説明:本明細書で使用するU-Bootのバージョンは1.1.6であり、プラットフォームはS 3 C 2440である.
目次
一、紹介
1.1タグリスト
二、タグ保管の住所を設定する
2.1関連する構造体定義
2.2タグ格納先の設定
三、タグの設定
3.1タグATAGの設定CORE
3.2メモリタグATAGの設定MEM
3.3コマンドラインタグATAGの設定CMDLINE
3.4 ATAGの設定NONE
一、紹介
U-BootとLinuxカーネルのインタラクションは一方向であり,U-Bootは各種パラメータをナハに伝達する.同時に実行できないため、転送方法は1つしかありません.U-Bootはパラメータを所定の場所に置いた後、カーネルを起動し、カーネルが起動した後、この場所からパラメータを取得します.
1.1タグリスト
パラメータを格納する場所を約束するほか,パラメータの構造を規定する.Linux2.4.x以降のカーネルは、パラメータをタグリスト(tagged list)として渡します.タグはデータ構造です.タグリストは、隣接して格納されている複数のタグです.タグリストはATAG_をタグするCOREで始まり、ATAGE_でNONE終了.
タグ付けされたデータ構造はtagであり、これは偶発的なtagである.ヘッダ構造と結合体(union)組成.tag_ヘッダ構造体は、メモリを表すかコマンドラインパラメータを表すかなど、タグのタイプと長さを表す.メモリ=を表すときにtag_を使用するなど、異なるタイプのタグに対して異なる連合体を使用します.men 32は、コマンドラインの場合tag_を使用することを示すcmdline.その定義はinclude/asm-arm/setupである.cファイルにあります.
/*
 * The new way of passing information: a list of tagged entries
 */

/* The list ends with an ATAG_NONE node. */
#define ATAG_NONE	0x00000000

struct tag_header {
	u32 size;
	u32 tag;
};

/* The list must start with an ATAG_CORE node */
#define ATAG_CORE	0x54410001

struct tag_core {
	u32 flags;		/* bit 0 = read-only */
	u32 pagesize;
	u32 rootdev;
};

/* it is allowed to have multiple ATAG_MEM nodes */
#define ATAG_MEM	0x54410002

struct tag_mem32 {
	u32	size;
	u32	start;	/* physical start address */
};

/* VGA text type displays */
#define ATAG_VIDEOTEXT	0x54410003

struct tag_videotext {
	u8		x;
	u8		y;
	u16		video_page;
	u8		video_mode;
	u8		video_cols;
	u16		video_ega_bx;
	u8		video_lines;
	u8		video_isvga;
	u16		video_points;
};

/* describes how the ramdisk will be used in kernel */
#define ATAG_RAMDISK	0x54410004

struct tag_ramdisk {
	u32 flags;	/* bit 0 = load, bit 1 = prompt */
	u32 size;	/* decompressed ramdisk size in _kilo_ bytes */
	u32 start;	/* starting block of floppy-based RAM disk image */
};

/* describes where the compressed ramdisk image lives (virtual address) */
/*
 * this one accidentally used virtual addresses - as such,
 * its depreciated.
 */
#define ATAG_INITRD	0x54410005

/* describes where the compressed ramdisk image lives (physical address) */
#define ATAG_INITRD2	0x54420005

struct tag_initrd {
	u32 start;	/* physical start address */
	u32 size;	/* size of compressed ramdisk image in bytes */
};

/* board serial number. "64 bits should be enough for everybody" */
#define ATAG_SERIAL	0x54410006

struct tag_serialnr {
	u32 low;
	u32 high;
};

/* board revision */
#define ATAG_REVISION	0x54410007

struct tag_revision {
	u32 rev;
};

/* initial values for vesafb-type framebuffers. see struct screen_info
 * in include/linux/tty.h
 */
#define ATAG_VIDEOLFB	0x54410008

struct tag_videolfb {
	u16		lfb_width;
	u16		lfb_height;
	u16		lfb_depth;
	u16		lfb_linelength;
	u32		lfb_base;
	u32		lfb_size;
	u8		red_size;
	u8		red_pos;
	u8		green_size;
	u8		green_pos;
	u8		blue_size;
	u8		blue_pos;
	u8		rsvd_size;
	u8		rsvd_pos;
};

/* command line: \0 terminated string */
#define ATAG_CMDLINE	0x54410009

struct tag_cmdline {
	char	cmdline[1];	/* this is the minimum size */
};

/* acorn RiscPC specific information */
#define ATAG_ACORN	0x41000101

struct tag_acorn {
	u32 memc_control_reg;
	u32 vram_pages;
	u8 sounddefault;
	u8 adfsdrives;
};

/* footbridge memory clock, see arch/arm/mach-footbridge/arch.c */
#define ATAG_MEMCLK	0x41000402

struct tag_memclk {
	u32 fmemclk;
};

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

#define tag_next(t)	((struct tag *)((u32 *)(t) + (t)->hdr.size))
#define tag_size(type)	((sizeof(struct tag_header) + sizeof(struct type)) >> 2) //???

二、タグ保管の住所を設定する
2.1関連する構造体定義
構造体bdには、タグが格納されたアドレスが格納されている.bd構造体はgd構造体の1つであり、include/asm-arm/global_に定義されたgd構造体を見てみましょう.data.hファイル内:
typedef	struct	global_data {
	bd_t		*bd;//        ,     ,  u-boot.h 
	unsigned long	flags;//    ,           
	unsigned long	baudrate;//       
	unsigned long	have_console;
	/* serial_init() was called         ,    1 */
	unsigned long	reloc_off;	
	/* 
	 *Relocation Offset      ,                      ,   0
        */
	unsigned long	env_addr;	/*       */
	unsigned long	env_valid;	/*     CRC      */
	unsigned long	fb_base;	/*       */
#ifdef CONFIG_VFD
	unsigned char	vfd_type;	/*     */
#endif
#if 0
	unsigned long	cpu_clk;	/*cpu  */
	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;
受け取って、include/asm-arm/u-bootで定義されたbd構造体を見てみましょう.hファイル内:
typedef struct bd_info {
    int			bi_baudrate;	/*      */
    unsigned long	bi_ip_addr;	/*  IP   */
    unsigned char	bi_enetaddr[6]; /* MAC  */
    struct environment_s	       *bi_env;
    ulong	        bi_arch_number;	/*     id*/
    ulong	        bi_boot_params;	/*     */
    struct				/* RAM   */
    {
	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;

2.2タグ格納先の設定
board/smdk 2410/smdk 2410.cのboard_init関数はbi_を設定しましたboot_paramsパラメータ:
int board_init (void)
{
	S3C24X0_CLOCK_POWER * const clk_power = S3C24X0_GetBase_CLOCK_POWER();//                      ,          
	S3C24X0_GPIO * const gpio = S3C24X0_GetBase_GPIO();//  GPIO               

	/* to reduce PLL lock time, adjust the LOCKTIME register */
	clk_power->LOCKTIME = 0xFFFFFF;

	/* configure MPLL */
	clk_power->MPLLCON = ((M_MDIV << 12) + (M_PDIV << 4) + M_SDIV);

	/* some delay between MPLL and UPLL */
	delay (4000);

	/* configure UPLL */
	clk_power->UPLLCON = ((U_M_MDIV << 12) + (U_M_PDIV << 4) + U_M_SDIV);

	/* some delay between MPLL and UPLL */
	delay (8000);

	/* set up the I/O ports */
	gpio->GPACON = 0x007FFFFF;
	gpio->GPBCON = 0x00044555;
	gpio->GPBUP = 0x000007FF;
	gpio->GPCCON = 0xAAAAAAAA;
	gpio->GPCUP = 0x0000FFFF;
	gpio->GPDCON = 0xAAAAAAAA;
	gpio->GPDUP = 0x0000FFFF;
	gpio->GPECON = 0xAAAAAAAA;
	gpio->GPEUP = 0x0000FFFF;
	gpio->GPFCON = 0x000055AA;
	gpio->GPFUP = 0x000000FF;
	gpio->GPGCON = 0xFF95FFBA;
	gpio->GPGUP = 0x0000FFFF;
	gpio->GPHCON = 0x002AFAAA;
	gpio->GPHUP = 0x000007FF;

	/* arch number of SMDK2410-Board */
	gd->bd->bi_arch_number = MACH_TYPE_SMDK2410;

	/* adress of boot parameters */
	gd->bd->bi_boot_params = 0x30000100;

	icache_enable();  //  cpu/arm920t/cpu.c    
	dcache_enable();

	return 0;
}

三、タグの設定
U-BootはbootmコマンドでLinuxカーネルを起動し、bootmコマンドは吼えにdo_を呼び出す.bootm_linux関数を使用してカーネルを起動します.do_bootm_linux関数はlib_に定義されたタグを設定します.arm/armlinux.c中:
void do_bootm_linux (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
		     ulong addr, ulong *len_ptr, int verify)
{
	ulong len = 0, checksum;
	ulong initrd_start, initrd_end;
	ulong data;
	void (*theKernel)(int zero, int arch, uint params);
	image_header_t *hdr = &header;
	bd_t *bd = gd->bd;

#ifdef CONFIG_CMDLINE_TAG
	char *commandline = getenv ("bootargs");
#endif

	theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);
	  kernal    

	/*
	 * Check if there is an initrd image
	 */
	      initrd        ,                   ,          ,     。
initial RAM disk  Linux   RAM  (initrd)                     ,            。initrd                  ,                ,       initrd RAM     ,     。      Linux    ,initrd           。
	if (argc >= 3) {
		SHOW_BOOT_PROGRESS (9);

		addr = simple_strtoul (argv[2], NULL, 16);

		printf ("## Loading Ramdisk Image at %08lx ...
", addr); /* Copy header so we can blank CRC field for re-calculation */ #ifdef CONFIG_HAS_DATAFLASH if (addr_dataflash (addr)) { read_dataflash (addr, sizeof (image_header_t), (char *) &header); } else #endif memcpy (&header, (char *) addr, sizeof (image_header_t)); if (ntohl (hdr->ih_magic) != IH_MAGIC) { printf ("Bad Magic Number
"); SHOW_BOOT_PROGRESS (-10); do_reset (cmdtp, flag, argc, argv); } data = (ulong) & header; len = sizeof (image_header_t); checksum = ntohl (hdr->ih_hcrc); hdr->ih_hcrc = 0; if (crc32 (0, (unsigned char *) data, len) != checksum) { printf ("Bad Header Checksum
"); SHOW_BOOT_PROGRESS (-11); do_reset (cmdtp, flag, argc, argv); } SHOW_BOOT_PROGRESS (10); print_image_hdr (hdr); data = addr + sizeof (image_header_t); len = ntohl (hdr->ih_size); #ifdef CONFIG_HAS_DATAFLASH if (addr_dataflash (addr)) { read_dataflash (data, len, (char *) CFG_LOAD_ADDR); data = CFG_LOAD_ADDR; } #endif if (verify) { ulong csum = 0; printf (" Verifying Checksum ... "); csum = crc32 (0, (unsigned char *) data, len); if (csum != ntohl (hdr->ih_dcrc)) { printf ("Bad Data CRC
"); SHOW_BOOT_PROGRESS (-12); do_reset (cmdtp, flag, argc, argv); } printf ("OK
"); } SHOW_BOOT_PROGRESS (11); if ((hdr->ih_os != IH_OS_LINUX) || (hdr->ih_arch != IH_CPU_ARM) || (hdr->ih_type != IH_TYPE_RAMDISK)) { printf ("No Linux ARM Ramdisk Image
"); SHOW_BOOT_PROGRESS (-13); do_reset (cmdtp, flag, argc, argv); } #if defined(CONFIG_B2) || defined(CONFIG_EVB4510) || defined(CONFIG_ARMADILLO) /* *we need to copy the ramdisk to SRAM to let Linux boot */ memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); data = ntohl(hdr->ih_load); #endif /* CONFIG_B2 || CONFIG_EVB4510 */ /* * Now check if we have a multifile image */ } else if ((hdr->ih_type == IH_TYPE_MULTI) && (len_ptr[1])) { ulong tail = ntohl (len_ptr[0]) % 4; int i; SHOW_BOOT_PROGRESS (13); /* skip kernel length and terminator */ data = (ulong) (&len_ptr[2]); /* skip any additional image length fields */ for (i = 1; len_ptr[i]; ++i) data += 4; /* add kernel length, and align */ data += ntohl (len_ptr[0]); if (tail) { data += 4 - tail; } len = ntohl (len_ptr[1]); } else { /* * no initrd image */ SHOW_BOOT_PROGRESS (14); len = data = 0; } #ifdef DEBUG if (!data) { printf ("No initrd
"); } #endif if (data) { initrd_start = data; initrd_end = initrd_start + len; } else { initrd_start = 0; initrd_end = 0; } SHOW_BOOT_PROGRESS (15); debug ("## Transferring control to Linux (at address %08lx) ...
", (ulong) theKernel); #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); tag, Linux #ifdef CONFIG_SERIAL_TAG setup_serial_tag (¶ms); #endif #ifdef CONFIG_REVISION_TAG setup_revision_tag (¶ms); #endif #ifdef CONFIG_SETUP_MEMORY_TAGS setup_memory_tags (bd); #endif #ifdef CONFIG_CMDLINE_TAG setup_commandline_tag (bd, commandline); #endif #ifdef CONFIG_INITRD_TAG if (initrd_start && initrd_end) setup_initrd_tag (bd, initrd_start, initrd_end); #endif #if defined (CONFIG_VFD) || defined (CONFIG_LCD) setup_videolfb_tag ((gd_t *) gd); #endif setup_end_tag (bd); #endif /* we assume that the kernel is in place */ printf ("
Starting kernel ...

"); #ifdef CONFIG_USB_DEVICE { extern void udc_disconnect (void); udc_disconnect (); } #endif cleanup_before_linux (); cpu/arm920t/cpu.c : R0: 0 R1: ID, ARM(bd->bi_arch_number) R2: (bd->bi_boot_params) theKernel (0, bd->bi_arch_number, bd->bi_boot_params); }

3.1タグATAGの設定CORE
タグリストはATAG_をタグするCORE開始
static void setup_start_tag (bd_t *bd)
{
	params = (struct tag *) bd->bi_boot_params;

	params->hdr.tag = ATAG_CORE;
	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);//         
}

3.2メモリタグATAGの設定MEM
board/smdk 2410/smdk 2410.cのdram_init関数はbdのbi_を設定しましたdram構造体:
int dram_init (void)
{
	gd->bd->bi_dram[0].start = PHYS_SDRAM_1;
	gd->bd->bi_dram[0].size = PHYS_SDRAM_1_SIZE;

	return 0;
}

次に、メモリタグの構造体を示します.
static void setup_memory_tags (bd_t *bd)
{
	int i;

	for (i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
		params->hdr.tag = ATAG_MEM;
		params->hdr.size = tag_size (tag_mem32);

		params->u.mem.start = bd->bi_dram[i].start;
		params->u.mem.size = bd->bi_dram[i].size;

		params = tag_next (params);
	}
}

3.3コマンドラインタグATAGの設定CMDLINE
コマンドラインは、カーネルの動作を制御する文字列です.例えば「root=/dev/mtdblock 2 init=/linuxrc console=ttySAC 0」は、ルートファイルシステムがMTD 2パーティション上でシステム起動後に実行する最初のプログラムが/linuxrcであり、コンソールがttySAC 0であることを示す.
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);
}

3.4 ATAGの設定NONE
タグリストはATAG_をタグするNONE紹介.
static void setup_end_tag (bd_t *bd)
{
	params->hdr.tag = ATAG_NONE;
	params->hdr.size = 0;
}