设为首页 收藏本站
查看: 720|回复: 0

[经验分享] U-Boot与Linux内核的交互

[复制链接]

尚未签到

发表于 2015-12-11 09:03:46 | 显示全部楼层 |阅读模式
U-Boot与Linux内核的交互

  说明:本文所使用的U-Boot的版本是1.1.6,平台是S3C2440。
目录
一、简介
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将各类参数传递给讷河。由于他们不能同时运行,传递办法只能有一个个:U-Boot将参数放在某个约定的地方之后,在启动内核,内核启动后从这个地方获得参数。
1.1标记列表  除了约定好参数存放的地方外,还要规定参数的结构。Linux2.4.x以后的内核都以标记列表(tagged list)的形式来传递参数。标记就是一种数据结构;标记列表就是挨着存放的多个标记。标记列表以标记ATAG_CORE开始,以ATAGE_NONE结束。
  标记的数据结构为tag,它是偶一个tag_header结构和一个联合体(union)组成。tag_header结构体表示标记的类型及长度,比如是表示内存还是表示命令行参数等。对于不同类型的标记使用不同的联合体,比如表示内存=时使用tag_men32,表示命令行时使用tag_cmdline。其定定义在include/asm-arm/setup.c文件中。
  



[plain] view plaincopyprint?

  • /*
  • * 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) //???
/** The new way of passing information: a list of tagged entries*//* The list ends with an ATAG_NONE node. */#define ATAG_NONE0x00000000struct tag_header {u32 size;u32 tag;};/* The list must start with an ATAG_CORE node */#define ATAG_CORE0x54410001struct tag_core {u32 flags;/* bit 0 = read-only */u32 pagesize;u32 rootdev;};/* it is allowed to have multiple ATAG_MEM nodes */#define ATAG_MEM0x54410002struct tag_mem32 {u32size;u32start;/* physical start address */};/* VGA text type displays */#define ATAG_VIDEOTEXT0x54410003struct tag_videotext {u8x;u8y;u16video_page;u8video_mode;u8video_cols;u16video_ega_bx;u8video_lines;u8video_isvga;u16video_points;};/* describes how the ramdisk will be used in kernel */#define ATAG_RAMDISK0x54410004struct 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_INITRD0x54410005/* describes where the compressed ramdisk image lives (physical address) */#define ATAG_INITRD20x54420005struct 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_SERIAL0x54410006struct tag_serialnr {u32 low;u32 high;};/* board revision */#define ATAG_REVISION0x54410007struct tag_revision {u32 rev;};/* initial values for vesafb-type framebuffers. see struct screen_info* in include/linux/tty.h*/#define ATAG_VIDEOLFB0x54410008struct tag_videolfb {u16lfb_width;u16lfb_height;u16lfb_depth;u16lfb_linelength;u32lfb_base;u32lfb_size;u8red_size;u8red_pos;u8green_size;u8green_pos;u8blue_size;u8blue_pos;u8rsvd_size;u8rsvd_pos;};/* command line: \0 terminated string */#define ATAG_CMDLINE0x54410009struct tag_cmdline {charcmdline[1];/* this is the minimum size */};/* acorn RiscPC specific information */#define ATAG_ACORN0x41000101struct 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_MEMCLK0x41000402struct tag_memclk {u32 fmemclk;};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;};#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结构体的一项,我们先看gd结构体,其定义在include/asm-arm/global_data.h文件中:
  



[plain] view plaincopyprint?

  • 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;
typedefstructglobal_data {bd_t*bd;//开发板相关参数 ,结构体变量,参考u-boot.h unsigned longflags;//指示标志,如设备已经初始化标志等unsigned longbaudrate;//串行口通讯速率unsigned longhave_console;/* serial_init() was called 如果执行了该函数,则设置为1 */unsigned longreloc_off;/* *Relocation Offset 重定位偏移,就是实际定向的位置与编译连接时指定的位置之差,一般为0*/unsigned longenv_addr;/* 环境参数地址*/unsigned longenv_valid;/* 环境参数CRC检验有效标志*/unsigned longfb_base;/*帧缓冲区基地址*/#ifdef CONFIG_VFDunsigned charvfd_type;/* 显示类型*/#endif#if 0unsigned longcpu_clk;/*cpu时钟*/unsigned longbus_clk;    //总线时钟unsigned longram_size;/* RAM size */unsigned longreset_status;/* reset status register at boot */#endifvoid**jt;/* jump table 跳转表,用来登记"函数调用地址"*/} gd_t;接来下我们来看一下bd结构体,这个结构体定义在include/asm-arm/u-boot.h文件中:  
  



[plain] view plaincopyprint?

  • 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;
typedef struct bd_info {intbi_baudrate;/* 串口波特率*/unsigned longbi_ip_addr;/*  IP 地址*/unsigned charbi_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/smdk2410/smdk2410.c的board_init 函数设置了bi_boot_params 参数:
  



[plain] view plaincopyprint?

  • 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 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;
  • }
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 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中:
  



[plain] view plaincopyprint?

  • 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 ...\n", 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\n");
  •             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\n");
  •             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\n");
  •                 SHOW_BOOT_PROGRESS (-12);
  •                 do_reset (cmdtp, flag, argc, argv);
  •             }
  •             printf ("OK\n");
  •         }

  •         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\n");
  •             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)
  •             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\n");
  •     }
  • #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) ...\n",
  •            (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 ("\nStarting kernel ...\n\n");打印信息

  • #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);
  • }
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_TAGchar *commandline = getenv ("bootargs");#endiftheKernel = (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 ...\n", addr);/* Copy header so we can blank CRC field for re-calculation */#ifdef CONFIG_HAS_DATAFLASHif (addr_dataflash (addr)) {read_dataflash (addr, sizeof (image_header_t),(char *) &header);} else#endifmemcpy (&header, (char *) addr,sizeof (image_header_t));if (ntohl (hdr->ih_magic) != IH_MAGIC) {printf ("Bad Magic Number\n");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\n");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_DATAFLASHif (addr_dataflash (addr)) {read_dataflash (data, len, (char *) CFG_LOAD_ADDR);data = CFG_LOAD_ADDR;}#endifif (verify) {ulong csum = 0;printf ("   Verifying Checksum ... ");csum = crc32 (0, (unsigned char *) data, len);if (csum != ntohl (hdr->ih_dcrc)) {printf ("Bad Data CRC\n");SHOW_BOOT_PROGRESS (-12);do_reset (cmdtp, flag, argc, argv);}printf ("OK\n");}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\n");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)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;}#ifdefDEBUGif (!data) {printf ("No initrd\n");}#endifif (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) ...\n",(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_TAGsetup_serial_tag (¶ms);#endif#ifdef CONFIG_REVISION_TAGsetup_revision_tag (¶ms);#endif#ifdef CONFIG_SETUP_MEMORY_TAGSsetup_memory_tags (bd);#endif#ifdef CONFIG_CMDLINE_TAGsetup_commandline_tag (bd, commandline);#endif#ifdef CONFIG_INITRD_TAGif (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);#endifsetup_end_tag (bd);#endif/* we assume that the kernel is in place */printf ("\nStarting kernel ...\n\n");打印信息#ifdef CONFIG_USB_DEVICE{extern void udc_disconnect (void);udc_disconnect ();}#endifcleanup_before_linux ();启动之前先做一些清理工作cpu/arm920t/cpu.c调用内核需要传递的参数如下:R0:必须为0R1:机器类型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开始
  



[plain] view plaincopyprint?

  • 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);//指向当前标记的末尾
  • }
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/smdk2410/smdk2410.c的dram_init函数设置了bd的bi_dram结构体:
  



[plain] view plaincopyprint?

  • 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;
  • }
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;}  
  下面是这边内存标记的结构体:
  



[plain] view plaincopyprint?

  • 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.start;
  •         params->u.mem.size = bd->bi_dram.size;

  •         params = tag_next (params);
  •     }
  • }
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.start;params->u.mem.size = bd->bi_dram.size;params = tag_next (params);}}3.3设置命令行标记ATAG_CMDLINE  命令行就是一个字符串,用来控制内核的一些行为。比如“root=/dev/mtdblock2 init=/linuxrc console=ttySAC0 ”表示根文件系统在MTD2分区上系统启动后执行的第一个程序为/linuxrc,控制台是ttySAC0 。
  



[plain] view plaincopyprint?

  • 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);
  • }
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介绍。
  



[plain] view plaincopyprint?

  • static void setup_end_tag (bd_t *bd)
  • {
  •     params->hdr.tag = ATAG_NONE;
  •     params->hdr.size = 0;

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-149479-1-1.html 上篇帖子: linux 内核线程,信号量,链表实现算法 下篇帖子: U-boot引导Linux内核问题
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表