u-boot分析_uboot启动内核

2019-07-13 04:54发布

这里写图片描述
u-boot 内核启动的时候依赖于以下这两行代码: s = getenv("bootcmd"); ... run_command(s,0); 第一条命令是从nand把内核把读到到一个地址上去;第二条命令是从内核里面启动内核; 从哪里读?从kernel分区读;
读到哪里去?放到指定地址(0x30007fc0)去; 在PC机上,每一个硬盘前面都有一个分区表。对于嵌入式Linux来说,flash上面没有分区表,显然这个分区就和PC机上不一样;既然没有分区表,这些分区怎么体现?只能在源码里面写死的; 定义分区的源码如下: #define MTDPARTS_DEFAULT "mtdparts=nandflash0:256K@0(bootloader),"也即从0256K为bootloader "128k(params),"接下来的128K放的是uboot的环境变量 "2m(kernel)," 2M空间放的是kernel "-(root)" 剩下的是root分区 上面定义了各个分区的起始地址; 具体地址从uboot菜单中输入mtd命令即可。下面的这个图是我的四个分区: 这里写图片描述 所以 nand read.jffs2 0x30007fc0 kernel = nand read.jffs2 0x30007fc0 0x00060000 0x0x00200000 下面分析一下如何读,如何把2M的内核读到0x30007fc0处?
因为启动时do_bootm,所以可以猜测nand read 应该是do_nand函数,do_nand函数代码如下: int do_nand(cmd_tbl_t * cmdtp, int flag, int argc, char *argv[]) { int i, dev, ret; ulong addr, off, size; char *cmd, *s; nand_info_t *nand; int quiet = 0; const char *quiet_str = getenv("quiet"); /* at least two arguments please */ if (argc < 2) goto usage; if (quiet_str) quiet = simple_strtoul(quiet_str, NULL, 0) != 0; cmd = argv[1]; if (strcmp(cmd, "info") == 0) { putc(' '); for (i = 0; i < CFG_MAX_NAND_DEVICE; i++) { if (nand_info[i].name) printf("Device %d: %s, sector size %lu KiB ", i, nand_info[i].name, nand_info[i].erasesize >> 10); } return 0; } if (strcmp(cmd, "device") == 0) { if (argc < 3) { if ((nand_curr_device < 0) || (nand_curr_device >= CFG_MAX_NAND_DEVICE)) puts(" no devices available "); else printf(" Device %d: %s ", nand_curr_device, nand_info[nand_curr_device].name); return 0; } dev = (int)simple_strtoul(argv[2], NULL, 10); if (dev < 0 || dev >= CFG_MAX_NAND_DEVICE || !nand_info[dev].name) { puts("No such device "); return 1; } printf("Device %d: %s", dev, nand_info[dev].name); puts("... is now current device "); nand_curr_device = dev; #ifdef CFG_NAND_SELECT_DEVICE /* * Select the chip in the board/cpu specific driver */ board_nand_select_device(nand_info[dev].priv, dev); #endif return 0; } if (strcmp(cmd, "bad") != 0 && strcmp(cmd, "erase") != 0 && strncmp(cmd, "dump", 4) != 0 && strncmp(cmd, "read", 4) != 0 && strncmp(cmd, "write", 5) != 0 && strcmp(cmd, "scrub") != 0 && strcmp(cmd, "markbad") != 0 && strcmp(cmd, "biterr") != 0 && strcmp(cmd, "lock") != 0 && strcmp(cmd, "unlock") != 0 ) goto usage; /* the following commands operate on the current device */ if (nand_curr_device < 0 || nand_curr_device >= CFG_MAX_NAND_DEVICE || !nand_info[nand_curr_device].name) { puts(" no devices available "); return 1; } nand = &nand_info[nand_curr_device]; if (strcmp(cmd, "bad") == 0) { printf(" Device %d bad blocks: ", nand_curr_device); for (off = 0; off < nand->size; off += nand->erasesize) if (nand_block_isbad(nand, off)) printf(" %08x ", off); return 0; } /* * Syntax is: * 0 1 2 3 4 * nand erase [clean] [off size] */ if (strcmp(cmd, "erase") == 0 || strcmp(cmd, "scrub") == 0) { nand_erase_options_t opts; /* "clean" at index 2 means request to write cleanmarker */ int clean = argc > 2 && !strcmp("clean", argv[2]); int o = clean ? 3 : 2; int scrub = !strcmp(cmd, "scrub"); printf(" NAND %s: ", scrub ? "scrub" : "erase"); /* skip first two or three arguments, look for offset and size */ if (arg_off_size(argc - o, argv + o, nand, &off, &size) != 0) return 1; memset(&opts, 0, sizeof(opts)); opts.offset = off; opts.length = size; opts.jffs2 = clean; opts.quiet = quiet; if (scrub) { puts("Warning: " "scrub option will erase all factory set " "bad blocks! " " " "There is no reliable way to recover them. " " " "Use this command only for testing purposes " "if you " " " "are sure of what you are doing! " " Really scrub this NAND flash? "); if (getc() == 'y' && getc() == ' ') { opts.scrub = 1; } else { puts("scrub aborted "); return -1; } } ret = nand_erase_opts(nand, &opts); printf("%s ", ret ? "ERROR" : "OK"); return ret == 0 ? 0 : 1; } if (strncmp(cmd, "dump", 4) == 0) { if (argc < 3) goto usage; s = strchr(cmd, '.'); off = (int)simple_strtoul(argv[2], NULL, 16); if (s != NULL && strcmp(s, ".oob") == 0) ret = nand_dump_oob(nand, off); else ret = nand_dump(nand, off); return ret == 0 ? 1 : 0; } /* read write */ if (strncmp(cmd, "read", 4) == 0 || strncmp(cmd, "write", 5) == 0) { int read; if (argc < 4) goto usage; addr = (ulong)simple_strtoul(argv[2], NULL, 16); read = strncmp(cmd, "read", 4) == 0; /* 1 = read, 0 = write */ printf(" NAND %s: ", read ? "read" : "write"); if (arg_off_size(argc - 3, argv + 3, nand, &off, &size) != 0) return 1; s = strchr(cmd, '.'); if (s != NULL && (!strcmp(s, ".jffs2") || !strcmp(s, ".e") || !strcmp(s, ".i"))) { if (read) { /* read */ nand_read_options_t opts; memset(&opts, 0, sizeof(opts)); opts.buffer = (u_char*) addr; opts.length = size; opts.offset = off; opts.quiet = quiet; ret = nand_read_opts(nand, &opts); } else { /* write */ nand_write_options_t opts; memset(&opts, 0, sizeof(opts)); opts.buffer = (u_char*) addr; opts.length = size; opts.offset = off; /* opts.forcejffs2 = 1; */ opts.pad = 1; opts.blockalign = 1; opts.quiet = quiet; ret = nand_write_opts(nand, &opts); } } else { if (read) ret = nand_read(nand, off, &size, (u_char *)addr); else ret = nand_write(nand, off, &size, (u_char *)addr); } printf(" %d bytes %s: %s ", size, read ? "read" : "written", ret ? "ERROR" : "OK"); return ret == 0 ? 0 : 1; } if (strcmp(cmd, "markbad") == 0) { addr = (ulong)simple_strtoul(argv[2], NULL, 16); int ret = nand->block_markbad(nand, addr); if (ret == 0) { printf("block 0x%08lx successfully marked as bad ", (ulong) addr); return 0; } else { printf("block 0x%08lx NOT marked as bad! ERROR %d ", (ulong) addr, ret); } return 1; } if (strcmp(cmd, "biterr") == 0) { /* todo */ return 1; } if (strcmp(cmd, "lock") == 0) { int tight = 0; int status = 0; if (argc == 3) { if (!strcmp("tight", argv[2])) tight = 1; if (!strcmp("status", argv[2])) status = 1; } if (status) { ulong block_start = 0; ulong off; int last_status = -1; struct nand_chip *nand_chip = nand->priv; /* check the WP bit */ nand_chip->cmdfunc (nand, NAND_CMD_STATUS, -1, -1); printf("device is %swrite protected ", (nand_chip->read_byte(nand) & 0x80 ? "NOT " : "" ) ); for (off = 0; off < nand->size; off += nand->oobblock) { int s = nand_get_lock_status(nand, off); /* print message only if status has changed * or at end of chip */ if (off == nand->size - nand->oobblock || (s != last_status && off != 0)) { printf("%08x - %08x: %8d pages %s%s%s ", block_start, off-1, (off-block_start)/nand->oobblock, ((last_status & NAND_LOCK_STATUS_TIGHT) ? "TIGHT " : ""), ((last_status & NAND_LOCK_STATUS_LOCK) ? "LOCK " : ""), ((last_status & NAND_LOCK_STATUS_UNLOCK) ? "UNLOCK " : "")); } last_status = s; } } else { if (!nand_lock(nand, tight)) { puts("NAND flash successfully locked "); } else { puts("Error locking NAND flash "); return 1; } } return 0; } if (strcmp(cmd, "unlock") == 0) { if (arg_off_size(argc - 2, argv + 2, nand, &off, &size) < 0) return 1; if (!nand_unlock(nand, off, size)) { puts("NAND flash successfully unlocked "); } else { puts("Error unlocking NAND flash, " "write and erase will probably fail "); return 1; } return 0; } usage: printf("Usage: %s ", cmdtp->usage); return 1; } u-boot 在flash上的存储的内核称为uImage,uimage的格式:头部+真正的内核; 头部主要有:
in-load:加载地址,表示运行内核的时候,内核应该先将其放到哪里;
in_ep:入口地址,表示要运行内核的时候,直接跳到这个地址就可以了; 这里写图片描述 下面要开始分析如何启动内核,主要是do_bootm函数: int do_bootm (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]) { ulong iflag; ulong addr; ulong data, len, checksum; ulong *len_ptr; uint unc_len = CFG_BOOTM_LEN; int i, verify; char *name, *s; int (*appl)(int, char *[]); image_header_t *hdr = &header; 注释开始 这里就是uimage的头部,是一个结构体 typedef struct image_header { uint32_t ih_magic; uint32_t ih_hcrc; uint32_t ih_time; uint32_t ih_size; uint32_t ih_load; 表示内核运行的时候你要把它放在哪里。 uint32_t ih_ep; 运行内核的时候入口地址,之前设置的是0x30007fc0,只要不破坏uboot内存使用分配即可,因为sp后面还有几十M的空间。正是因为uimage中有个header,header结构体中有一个loadaddress。我们把uimage放在某个地址,bootm加上这个地址,去读出头部中的in_load,如果发现内核不在加载地址中,则需要把内核移动到这个加载地址中去,最后跳到in_ep去执行。 uint32_t ih_dcrc; uint8_t ih_os; uint8_t ih_arch; uint8_t ih_type; uint8_t ih_comp; uint8_t ih_name[IH_NMLEN]; } image_header_t; 注释结束 s = getenv ("verify"); verify = (s && (*s == 'n')) ? 0 : 1; if (argc < 2) { addr = load_addr; } else { addr = simple_strtoul(argv[1], NULL, 16); } SHOW_BOOT_PROGRESS (1); printf ("## Booting image at lx ... ", addr); #ifdef CONFIG_HAS_DATAFLASH if (addr_dataflash(addr)){ read_dataflash(addr, sizeof(image_header_t), (char *)&header); } else #endif memmove (&header, (char *)addr, sizeof(image_header_t)); if (ntohl(hdr->ih_magic) != IH_MAGIC) { #ifdef __I386__ if (fake_header(hdr, (void*)addr, -1) != NULL) { addr -= sizeof(image_header_t); verify = 0; } else #endif { puts ("Bad Magic Number "); SHOW_BOOT_PROGRESS (-1); return 1; } } SHOW_BOOT_PROGRESS (2); data = (ulong)&header; len = sizeof(image_header_t); checksum = ntohl(hdr->ih_hcrc); hdr->ih_hcrc = 0; if (crc32 (0, (uchar *)data, len) != checksum) { puts ("Bad Header Checksum "); SHOW_BOOT_PROGRESS (-2); return 1; } SHOW_BOOT_PROGRESS (3); #ifdef CONFIG_HAS_DATAFLASH if (addr_dataflash(addr)){ len = ntohl(hdr->ih_size) + sizeof(image_header_t); read_dataflash(addr, len, (char *)CFG_LOAD_ADDR); addr = CFG_LOAD_ADDR; } #endif print_image_hdr ((image_header_t *)addr); data = addr + sizeof(image_header_t); len = ntohl(hdr->ih_size); if (verify) { puts (" Verifying Checksum ... "); if (crc32 (0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)) { printf ("Bad Data CRC "); SHOW_BOOT_PROGRESS (-3); return 1; } puts ("OK "); } SHOW_BOOT_PROGRESS (4); len_ptr = (ulong *)data; #if defined(__PPC__) if (hdr->ih_arch != IH_CPU_PPC) #elif defined(__ARM__) if (hdr->ih_arch != IH_CPU_ARM) #elif defined(__I386__) if (hdr->ih_arch != IH_CPU_I386) #elif defined(__mips__) if (hdr->ih_arch != IH_CPU_MIPS) #elif defined(__nios__) if (hdr->ih_arch != IH_CPU_NIOS) #elif defined(__M68K__) if (hdr->ih_arch != IH_CPU_M68K) #elif defined(__microblaze__) if (hdr->ih_arch != IH_CPU_MICROBLAZE) #elif defined(__nios2__) if (hdr->ih_arch != IH_CPU_NIOS2) #elif defined(__blackfin__) if (hdr->ih_arch != IH_CPU_BLACKFIN) #elif defined(__avr32__) if (hdr->ih_arch != IH_CPU_AVR32) #else # error Unknown CPU type #endif { printf ("Unsupported Architecture 0x%x ", hdr->ih_arch); SHOW_BOOT_PROGRESS (-4); return 1; } SHOW_BOOT_PROGRESS (5); switch (hdr->ih_type) { case IH_TYPE_STANDALONE: name = "Standalone Application"; if (argc > 2) { hdr->ih_load = htonl(simple_strtoul(argv[2], NULL, 16)); } break; case IH_TYPE_KERNEL: name = "Kernel Image"; break; case IH_TYPE_MULTI: name = "Multi-File Image"; len = ntohl(len_ptr[0]); data += 8; for (i=1; len_ptr[i]; ++i) data += 4; break; default: printf ("Wrong Image Type for %s command ", cmdtp->name); SHOW_BOOT_PROGRESS (-5); return 1; } SHOW_BOOT_PROGRESS (6); iflag = disable_interrupts(); #ifdef CONFIG_AMIGAONEG3SE icache_disable(); invalidate_l1_instruction_cache(); flush_data_cache(); dcache_disable(); #endif switch (hdr->ih_comp) { case IH_COMP_NONE: if(ntohl(hdr->ih_load) == addr) {如果ih_load==addr,则打印xip printf (" XIP %s ... ", name); } else { #if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG) size_t l = len; void *to = (void *)ntohl(hdr->ih_load); void *from = (void *)data; printf (" Loading %s ... ", name); while (l > 0) { size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l; WATCHDOG_RESET(); memmove (to, from, tail); to += tail; from += tail; l -= tail; } #else 否则就要移动真正的内核 memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);这里就是把真正内核开始的data移动到ih_load加载地址中去。韦东山开发板的内核真正地址为0x30008000,而内核头部的起始地址是0x30007fc0,两者相差64字节,正好是头部的长度,这样就不用做搬运真正的内核的工作了。可以加快启动速度。 #endif } break; case IH_COMP_GZIP: printf (" Uncompressing %s ... ", name); if (gunzip ((void *)ntohl(hdr->ih_load), unc_len, (uchar *)data, &len) != 0) { puts ("GUNZIP ERROR - must RESET board to recover "); SHOW_BOOT_PROGRESS (-6); do_reset (cmdtp, flag, argc, argv); } break; #ifdef CONFIG_BZIP2 case IH_COMP_BZIP2: printf (" Uncompressing %s ... ", name); i = BZ2_bzBuffToBuffDecompress ((char*)ntohl(hdr->ih_load), &unc_len, (char *)data, len, CFG_MALLOC_LEN < (4096 * 1024), 0); if (i != BZ_OK) { printf ("BUNZIP2 ERROR %d - must RESET board to recover ", i); SHOW_BOOT_PROGRESS (-6); udelay(100000); do_reset (cmdtp, flag, argc, argv); } break; #endif default: if (iflag) enable_interrupts(); printf ("Unimplemented compression type %d ", hdr->ih_comp); SHOW_BOOT_PROGRESS (-7); return 1; } puts ("OK "); SHOW_BOOT_PROGRESS (7); switch (hdr->ih_type) { case IH_TYPE_STANDALONE: if (iflag) enable_interrupts(); if (((s = getenv("autostart")) != NULL) && (strcmp(s,"no") == 0)) { char buf[32]; sprintf(buf, "%lX", len); setenv("filesize", buf); return 0; } appl = (int (*)(int, char *[]))ntohl(hdr->ih_ep); (*appl)(argc-1, &argv[1]); return 0; case IH_TYPE_KERNEL: case IH_TYPE_MULTI: break; default: if (iflag) enable_interrupts(); printf ("Can't boot image type %d ", hdr->ih_type); SHOW_BOOT_PROGRESS (-8); return 1; } SHOW_BOOT_PROGRESS (8); switch (hdr->ih_os) { default: case IH_OS_LINUX: #ifdef CONFIG_SILENT_CONSOLE fixup_silent_linux(); #endif do_bootm_linux (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; case IH_OS_NETBSD: do_bootm_netbsd (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #ifdef CONFIG_LYNXKDI case IH_OS_LYNXOS: do_bootm_lynxkdi (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #endif case IH_OS_RTEMS: do_bootm_rtems (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #if (CONFIG_COMMANDS & CFG_CMD_ELF) case IH_OS_VXWORKS: do_bootm_vxworks (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; case IH_OS_QNX: do_bootm_qnxelf (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #endif #ifdef CONFIG_ARTOS case IH_OS_ARTOS: do_bootm_artos (cmdtp, flag, argc, argv, addr, len_ptr, verify); break; #endif } SHOW_BOOT_PROGRESS (-9); #ifdef DEBUG puts (" ## Control returned to monitor - resetting... "); do_reset (cmdtp, flag, argc, argv); #endif return 1; } do_bootm有两个作用:
作用1:读取内核头部将内核移动到合适地方,还有一些校验
作用2:启动内核,用的是do_bootm_linux函数。在跳到ih_ep入口之前还要uboot设置内核启动参数,然后才是跳到ih_ep启动内核。 do_bootm_linux函数开始的代码如下: 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); if (argc >= 3) { SHOW_BOOT_PROGRESS (9); addr = simple_strtoul (argv[2], NULL, 16); printf ("## Loading Ramdisk Image at lx ... ", addr); #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 Checksumn"); 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) memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len); data = ntohl(hdr->ih_load); #endif } else if ((hdr->ih_type == IH_TYPE_MULTI) && (len_ptr[1])) { ulong tail = ntohl (len_ptr[0]) % 4; int i; SHOW_BOOT_PROGRESS (13); data = (ulong) (&len_ptr[2]); for (i = 1; len_ptr[i]; ++i) data += 4; data += ntohl (len_ptr[0]); if (tail) { data += 4 - tail; } len = ntohl (len_ptr[1]); } else { SHOW_BOOT_PROGRESS (14); len = data = 0; } #ifdef DEBUG if (!data) { printf ("No initrdn"); } #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 lx) ... ", (ulong) theKernel); #if defined (CONFIG_SETUP_MEMORY_TAGS) || uboot设置参数在这里 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); #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 printf (" Starting kernel ... "); #ifdef CONFIG_USB_DEVICE { extern void udc_disconnect (void); udc_disconnect (); } #endif cleanup_before_linux (); theKernel (0, bd->bi_arch_number, bd->bi_boot_params);启动内核在这里 } do_bootm_linux 作用1:设置内核启动参数,参数的格式是tag,对于韦东山的开发板地址是0x30000100,下面分析两个参数,其中setup_start_tag和setup_end_tag是必须的。 static void setup_start_tag (bd_t *bd) { params = (struct tag *) bd->bi_boot_params;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); } 作用2:跳到入口地址去是
theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
这样就启动内核了!!!
具体bi_boot_params是多少搜索代码可以知道,其实韦东山是在自己的100ask24x0.c中自己定义的。
setup_start_tag之后我们得到: 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); } 0x30000100|size|tag|flag|page_size|root_dev|
其中header_size=sizeof(struct tag_header) + (sizeof(struct type) >> 2)
也就是说执行完这个函数之后,要明白在内核启动参数区域都放了大小是多少的参数。
执行完setup_memory_tag函数之后: #ifdef CONFIG_SETUP_MEMORY_TAGS 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); } } #endif 这时存储内核启动参数的区域类似于setup_start_tag
开始是size|tag|size|start|
下面是start_commandline_tag static void setup_commandline_tag (bd_t *bd, char *commandline) { char *p; if (!commandline) return; 把命令前面的空格给干掉 for (p = commandline; *p == ' '; p++); if (*p == '