一、引导zImage
程序跳到内存中的main函数之后,初始化串口和nand flash,然后引导内核。
myboot_loader.rar (将后缀名改为tar.gz, 卡在nand_read_page中大约20秒)
myboot_loader_noprint.rar (将后缀名改为tar.gz,卡在nand_read_page中大约20秒,并且有时会直接卡死)
二、代码
稍微整理一下代码,将头文件都放在include目录下。每一个模块一个头文件,这样结构比较清晰。
root@ubuntu:~/myboot_loader# tree
.
├── boot_zImage.c
├── include
│ ├── nand.h
│ ├── string.h
│ ├── uart.h
│ └── vsprintf.h
├── main.c
├── Makefile
├── nand.c
├── sdram.c
├── start.S
├── uart.c
├── u-boot.lds
└── vsprintf.c
1 directory, 13 files
2.1 main.c
点击(此处)折叠或打开
- #include "uart.h"
- #include "nand.h"
-
- extern int boot_zImage(unsigned long from, unsigned long size);
- void main(void)
- {
- uart_init(); //初始化串口
- nand_init();
- uart_printf("now boot the kernel\n");
-
- boot_zImage(0x200000, 0x200000);
- }
2.2 boot_zImage.c 取自tq2440的u-boot
boot_zImage函数,
点击(此处)折叠或打开
- #include "uart.h"
- #include "nand.h"
- #include "string.h"
-
- #define LINUX_KERNEL_OFFSET 0x8000
- #define LINUX_PARAM_OFFSET 0x100
- #define LINUX_PAGE_SIZE 0x00001000
- #define LINUX_PAGE_SHIFT 12
- #define LINUX_ZIMAGE_MAGIC 0x016f2818
- #define DRAM_SIZE 0x04000000
- #define CONFIG_BOOTARGS "noinitrd root=/dev/mtdblock2 init=/linuxrc console=ttySAC0 mem=128M"
- #define COMMAND_LINE_SIZE 256
- #define MACH_TYPE_S3C2440 168
- struct param_struct {
- union {
- struct {
- unsigned long page_size; /* 0 */
- unsigned long nr_pages; /* 4 */
- unsigned long ramdisk_size; /* 8 */
- unsigned long flags; /* 12 */
- #define FLAG_READONLY 1
- #define FLAG_RDLOAD 4
- #define FLAG_RDPROMPT 8
- unsigned long rootdev; /* 16 */
- unsigned long video_num_cols; /* 20 */
- unsigned long video_num_rows; /* 24 */
- unsigned long video_x; /* 28 */
- unsigned long video_y; /* 32 */
- unsigned long memc_control_reg; /* 36 */
- unsigned char sounddefault; /* 40 */
- unsigned char adfsdrives; /* 41 */
- unsigned char bytes_per_char_h; /* 42 */
- unsigned char bytes_per_char_v; /* 43 */
- unsigned long pages_in_bank[4]; /* 44 */
- unsigned long pages_in_vram; /* 60 */
- unsigned long initrd_start; /* 64 */
- unsigned long initrd_size; /* 68 */
- unsigned long rd_start; /* 72 */
- unsigned long system_rev; /* 76 */
- unsigned long system_serial_low; /* 80 */
- unsigned long system_serial_high; /* 84 */
- unsigned long mem_fclk_21285; /* 88 */
- } s;
- char unused[256];
- } u1;
- union {
- char paths[8][128];
- struct {
- unsigned long magic;
- char n[1024 - sizeof(unsigned long)];
- } s;
- } u2;
- char commandline[COMMAND_LINE_SIZE];
- };
-
- /*
- * Disable IRQs
- */
- #define local_irq_disable() \
- ({ \
- unsigned long temp; \
- __asm__ __volatile__( \
- "mrs %0, cpsr @ local_irq_disable\n" \
- " orr %0, %0, #128\n" \
- " msr cpsr_c, %0" \
- : "=r" (temp) \
- : \
- : "memory", "cc"); \
- })
-
- static inline void cpu_arm920_cache_clean_invalidate_all(void)
- {
- __asm__(
- " mov r1, #0\n"
- " mov r1, #7 << 5\n" /* 8 segments */
- "1: orr r3, r1, #63 << 26\n" /* 64 entries */
- "2: mcr p15, 0, r3, c7, c14, 2\n" /* clean & invalidate D index */
- " subs r3, r3, #1 << 26\n"
- " bcs 2b\n" /* entries 64 to 0 */
- " subs r1, r1, #1 << 5\n"
- " bcs 1b\n" /* segments 7 to 0 */
- " mcr p15, 0, r1, c7, c5, 0\n" /* invalidate I cache */
- " mcr p15, 0, r1, c7, c10, 4\n" /* drain WB */
- );
- }
-
- void cache_clean_invalidate(void)
- {
- cpu_arm920_cache_clean_invalidate_all();
- }
-
- static inline void cpu_arm920_tlb_invalidate_all(void)
- {
- __asm__(
- "mov r0, #0\n"
- "mcr p15, 0, r0, c7, c10, 4\n" /* drain WB */
- "mcr p15, 0, r0, c8, c7, 0\n" /* invalidate I & D TLBs */
- );
- }
-
- void tlb_invalidate(void)
- {
- cpu_arm920_tlb_invalidate_all();
- }
-
-
- void call_linux(long a0, long a1, long a2)
- {
- local_irq_disable();
- cache_clean_invalidate();
- tlb_invalidate();
-
- __asm__(
- "mov r0, %0\n"
- "mov r1, %1\n"
- "mov r2, %2\n"
- "mov ip, #0\n"
- "mcr p15, 0, ip, c13, c0, 0\n" /* zero PID */
- "mcr p15, 0, ip, c7, c7, 0\n" /* invalidate I,D caches */
- "mcr p15, 0, ip, c7, c10, 4\n" /* drain write buffer */
- "mcr p15, 0, ip, c8, c7, 0\n" /* invalidate I,D TLBs */
- "mrc p15, 0, ip, c1, c0, 0\n" /* get control register */
- "bic ip, ip, #0x0001\n" /* disable MMU */
- "mcr p15, 0, ip, c1, c0, 0\n" /* write control register */
- "mov pc, r2\n"
- "nop\n"
- "nop\n"
- : /* no outpus */
- : "r" (a0), "r" (a1), "r" (a2)
- : "r0","r1","r2","ip"
- );
- }
-
- /*
- * pram_base: base address of linux paramter
- */
- static void setup_linux_param(unsigned long param_base)
- {
- struct param_struct *params = (struct param_struct *)param_base;
- char *linux_cmd = CONFIG_BOOTARGS ;
-
- memset((unsigned char*)params, 0, sizeof(struct param_struct));
-
- params->u1.s.page_size = LINUX_PAGE_SIZE;
- params->u1.s.nr_pages = (DRAM_SIZE >> LINUX_PAGE_SHIFT);
-
- /* set linux command line */
- memcpy(params->commandline, linux_cmd, strlen(linux_cmd) + 1);
- }
-
- int boot_zImage(unsigned long from, unsigned long size)
- {
- int ret;
- unsigned long boot_mem_base; /* base address of bootable memory */
- unsigned long to;
- unsigned long mach_type;
-
- boot_mem_base = 0x30000000;
-
- /* copy kerne image */
- to = boot_mem_base + LINUX_KERNEL_OFFSET;
- uart_printf("Copy kernel from 0x%08lx to 0x%08lx, size = 0x%08lx ...\n ", from, to, size);
-
- nand_read_page((unsigned char *)to, (unsigned long)from, (int)size);
-
- uart_printf("read over! next check \n");
-
- //uart_printf("read ok!\n");
-
- if (*(unsigned long *)(to + 9*4) != LINUX_ZIMAGE_MAGIC) {
- uart_printf("Warning: this binary is not compressed linux kernel image\n");
- uart_printf("zImage magic = 0x%08lx\n", *(unsigned long *)(to + 9*4));
- return -1;
- }
-
- /* Setup linux parameters and linux command line */
- setup_linux_param(boot_mem_base + LINUX_PARAM_OFFSET);
-
- /* Get machine type */
- mach_type = MACH_TYPE_S3C2440;
- // printk("MACH_TYPE = %d\n", mach_type);
-
- /* Go Go Go */
- uart_printf("NOW, Booting Linux......\n");
- call_linux(0, mach_type, to);
-
- return 0;
- }
a. 首先将内核从nand flash的0x00200000复制到0x30008000,复制大小为0x00200000
b. 检查文件头是否正确
c. 在u-boot与内核约定的参数起始地址0x30000100处,设置linux的启动参数
d. 最后启动内核
不过这个程序还存在问题:启动时会卡在nand_read_page处大约20秒左右,下一步看问题出在什么地方?
三、
3.1 这样一个最最最最基本的bootloader就完成了,
root@ubuntu:~/myboot_loader# ll u-boot.bin
-rwxr-xr-x 1 root root
6796 2012-05-31 00:44 u-boot.bin*
大小是6796,大约是6.7K.
3.2 这个bootloader可以进一步精简,把vsprintf去掉之后
root@ubuntu:~/myboot_loader_noprint# ll u-boot.bin
-rwxr-xr-x 1 root root 2868 2012-05-31 00:48 u-boot.bin*
大小只有2868个字节。当然如果是小于4K,程序就可以直接在sram中进行,那么先把bootloader复制到内存这一步也可以省略,相信代码可以更小。

