最简单bootloader包含以下几个内容
第一阶段:
(1)关看门狗
(2)设置时钟
(3)初始化SDRAM
(4)重定位:bootloader可能大于4K,
把flash中的bootloader拷贝到SDRAM中。
(5)跳转到main
第二阶段:
(6)初始化串口,内核启动打印参数
(7)设置启动参数,供内核启动时解析使用
(8)跳转启动内核
一.编写第1阶段
1.bootloader目标:启动内核。
(1)从flash把内核读入内存
能操作flash、初始化内存、初始化时钟
(2)启动内核
设置参数(bootloader与内核约定好地址,存放一些内核启动的参数,供内核启动使用),跳转执行。
最简单的bootloader的编写步骤:
1.1 初始化硬件:关看门狗、设置时钟、设置SDRAM、初始化NAND FLASH
1.2 如果bootloader比较大,要把它重定位到SDRAM
1.3 把内核从NAND FLASH读到SDRAM
1.4 设置"要传给内核的参数"
1.5 跳转执行内核
1.1 初始化硬件:关看门狗、设置时钟、设置SDRAM、初始化NAND FLASH
1.2 如果bootloader比较大,要把它重定位到SDRAM
1.3 把内核从NAND FLASH读到SDRAM
1.4 设置"要传给内核的参数"
1.5 跳转执行内核
2.首先写start.S,主要内容如下:
/* 1. 关看门狗 */
- ldr r0, =0x53000000
- mov r1, #0
- str r1, [r0]
/* 2. 设置时钟 */
- <span style="white-space:pre"> </span>ldr r0, =0x4c000014
- mov r1, #0x03; // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1
- str r1, [r0]
- /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */
- mrc p15, 0, r1, c1, c0, 0 /* 读出控制寄存器 */
- orr r1, r1, #0xc0000000 /* 设置为“asynchronous bus mode” */
- mcr p15, 0, r1, c1, c0, 0 /* 写入控制寄存器 */
- /* MPLLCON = S3C2440_MPLL_200MHZ */
- ldr r0, =0x4c000004
- ldr r1, =S3C2440_MPLL_200MHZ
- str r1, [r0]
- <span style="white-space:pre"> </span>#define S3C2440_MPLL_200MHZ ((0x5c<<12)|(0x01<<4)|(0x02))
- <span style="white-space:pre"> </span>#define MEM_CTL_BASE 0x48000000
/* 3. 初始化SDRAM */
- ldr r0, =MEM_CTL_BASE
- adr r1, sdram_config /* sdram_config的当前地址 */
- add r3, r0, #(13*4)
- 1:
- ldr r2, [r1], #4
- str r2, [r0], #4
- cmp r0, r3
- bne 1b
- sdram_config:
- .long 0x22011110 //BWSCON
- .long 0x00000700 //BANKCON0
- .long 0x00000700 //BANKCON1
- .long 0x00000700 //BANKCON2
- .long 0x00000700 //BANKCON3
- .long 0x00000700 //BANKCON4
- .long 0x00000700 //BANKCON5
- .long 0x00018005 //BANKCON6
- .long 0x00018005 //BANKCON7
- .long 0x008C04F4 //REFRESH
- .long 0x000000B1 //BANKSIZE
- .long 0x00000030 //MRSRB6
- .long 0x00000030 //MRSRB7
/* 4. 重定位 : 把bootloader本身的代码从flash复制到它的链接地址去 2440 sdram 3000 0000-3400 0000*/
启动分析
(1)如果从nor启动,则拷贝nor中的boot到内存中的链接地址
(2)如果从nand启动,则上电后系统自动拷贝bootloader前4K到内存并开始执行,此时需要这小于4K的代码,将nand中的bootloader复制到sdram中的链接地址处。
编写init.c实现copy_code_to_sdram:(判断启动方式后复制)见init.c.....
- void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
- {
- int i = 0;
- /* 如果是NOR启动 */
- if (isBootFromNorFlash())
- {
- while (i < len)
- {
- dest[i] = src[i];
- i++;
- }
- }
- else
- {
- //nand_init();
- nand_read((unsigned int)src, dest, len);
- }
- }
需要判断是从哪启动。
- int isBootFromNorFlash(void)
- {
- volatile int *p = (volatile int *)0;
- int val;
- val = *p;
- *p = 0x12345678;
- if (*p == 0x12345678)
- {
- /* 写成功, 是nand启动 */
- *p = val;
- return 0;
- }
- else
- {
- /* NOR不能像内存一样写 */
- return 1;
- }
- }
- void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
- {
- int i = 0;
- /* 如果是NOR启动 */
- if (isBootFromNorFlash())
- {
- while (i < len)
- {
- dest[i] = src[i];//从原地址读出一个值给目的地址
- i++;
- }
- }
- else
- {
- //nand_init();
- nand_read((unsigned int)src, dest, len);
- }
- }
第二个参数链接地址:r1:链接地址 _start=0X33f80000
第三个参数长度:r2:__bss_start - _start(参考链接脚本)0X33f80000开始存放
如下:
- ldr sp, =0x34000000
- bl nand_init
- mov r0, #0
- ldr r1, =_start
- ldr r2, =__bss_start
- sub r2, r2, r1
- bl copy_code_to_sdram
- bl clear_bss
清除bss段:
bl clear_bss:(init.c中)
- void clear_bss(void)
- {
- extern int __bss_start, __bss_end;
- int *p = &__bss_start;
- for (; p < &__bss_end; p++)
- *p = 0;
- }
接下来写nand_init和 nand_read函数:(内核也存在此处所以肯定需要初始化)...
参考2440手册和nand flash 手册,进行nand的初始化和复制:总的程序:
- /* 4. 重定位 : 把bootloader本身的代码从flash复制到它的链接地址去 */
- ldr sp, =0x34000000
- bl nand_init
- mov r0, #0
- ldr r1, =_start
- ldr r2, =__bss_start
- sub r2, r2, r1
- bl copy_code_to_sdram
- bl clear_bss
/* 5. 执行main */
- ldr lr, =halt
- ldr pc, =main
- halt:
- b halt
/* 0. 帮内核设置串口: 内核启动的开始部分会从串口打印一些信息,但是内核一开始没有初始化串口所以要完成初始化串口不然后内核启动的时候可能出错 */
- uart0_init();
/* 1. 从NAND FLASH里把内核读入内存 */
0x60000+64(64K的头部)
内核地址0x30008000(内核中配置好的地址)nand_read的实现
- <span style="white-space:pre"> </span>/* 1. 从NAND FLASH里把内核读入内存 */
- <span style="white-space:pre"> </span>puts("Copy kernel from nand\n\r");
- <span style="white-space:pre"> </span>nand_read(0x60000+64, (unsigned char *)0x30008000, 0x200000);
- <span style="white-space:pre"> </span>puthex(0x1234ABCD);
- <span style="white-space:pre"> </span>puts("\n\r");
- <span style="white-space:pre"> </span>puthex(*p);
- <span style="white-space:pre"> </span>puts("\n\r");
/* 2. 设置参数 */
内核和UBOOT约定好在某个地址存放启动参数,比如此处是0x30000100开始存放启动参数,uboot将参数存放到0x30000100开始的地方,内核启动时会从这里取出参数。实现代码如下:
下面几个函数,都向地址内写入了
(1)参数代号
(2)本参数所占内存大小
(3)参数内容
(4)每个参数设置最后都指向了下一参数设置地址
- puts("Set boot params\n\r");
- setup_start_tag();
- setup_memory_tags();
- setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
- setup_end_tag();
/* 3. 跳转执行,启动内核 */
- puts("Boot kernel\n\r");
- theKernel = (void (*)(int, int, unsigned int))0x30008000;
- theKernel(0, 362, 0x30000100);
- /*
- * mov r0, #0
- * ldr r1, =362
- * ldr r2, =0x30000100
- * mov pc, #0x30008000
- */
- puts("Error!\n\r");
- /* 如果一切正常, 不会执行到这里 */
- return -1;
- Copy kernel from nand
- 0x1234ABCD
- 0xE1A00000
- Set boot params
- Boot kernel
- Uncompressing Linux...................................................................................................................... done, booting the kernel.
- Linux version 2.6.22.6 (book@book-desktop) (gcc version 3.4.5) #1 Fri Aug 23 15:33:35 CST 2013
- CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177
- Machine: SMDK2440
- Memory policy: ECC disabled, Data cache writeback
- CPU S3C2440A (id 0x32440001)
- S3C244X: core 200.000 MHz, memory 100.000 MHz, peripheral 50.000 MHz
- S3C24XX Clocks, (c) 2004 Simtec Electronics
- CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on
- CPU0: D VIVT write-back cache
- CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
- CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets
- Built 1 zonelists. Total pages: 16256
- Kernel command line: noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0
- irq: clearing subpending status 00000002
- PID hash table entries: 256 (order: 8, 1024 bytes)
- timer tcon=00000000, tcnt a2c1, tcfg 00000200,00000000, usec 00001eb8
- Console: colour dummy device 80x30
- Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)
- Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)
- Memory: 64MB = 64MB total
- Memory: 60976KB available (3264K code, 458K data, 140K init)
- Mount-cache hash table entries: 512
- CPU: Testing write buffer coherency: ok
- NET: Registered protocol family 16
- S3C2410 Power Management, (c) 2004 Simtec Electronics
- S3C2440: Initialising architecture
- S3C2440: IRQ Support
- S3C2440: Clock Support, DVS off
- S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics
- DMA channel 0 at c4800000, irq 33
- DMA channel 1 at c4800040, irq 34
- DMA channel 2 at c4800080, irq 35
- DMA channel 3 at c48000c0, irq 36
- SCSI subsystem initialized
- usbcore: registered new interface driver usbfs
- usbcore: registered new interface driver hub
- usbcore: registered new device driver usb
- NET: Registered protocol family 2
- IP route cache hash table entries: 1024 (order: 0, 4096 bytes)
- TCP established hash table entries: 2048 (order: 2, 16384 bytes)
- TCP bind hash table entries: 2048 (order: 1, 8192 bytes)
- TCP: Hash tables configured (established 2048 bind 2048)
- TCP reno registered
- NetWinder Floating Point Emulator V0.97 (double precision)
- Registering GDB sysrq handler
- JFFS2 version 2.2. (NAND) 漏 2001-2006 Red Hat, Inc.
- yaffs Aug 23 2013 15:33:07 Installing.
- io scheduler noop registered
- io scheduler anticipatory registered (default)
- io scheduler deadline registered
- io scheduler cfq registered
- Console: switching to colour frame buffer device 60x34
- fb0: s3c2410fb frame buffer device
- lp: driver loaded but no devices found
- ppdev: user-space parallel port driver
- S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics
- Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing enabled
- s3c2440-uart.0: s3c2410_serial0 at MMIO map 0x50000000 mem 0xf0400000 (irq = 70) is a S3C2440
- s3c2440-uart.1: s3c2410_serial1 at MMIO map 0x50004000 mem 0xf0404000 (irq = 73) is a S3C2440
- s3c2440-uart.2: s3c2410_serial2 at MMIO map 0x50008000 mem 0xf0408000 (irq = 76) is a S3C2440
- RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize
- loop: module loaded
- line 400 <DM9KS> I/O: c486a000, VID: 90000a46
- line 408 <DM9KS> I/O: c486a000, VID: 90000a46
- <DM9KS> error version, chip_revision = 0x19, chip_info = 0x0
- id_val=0
- S3C24XX NAND Driver, (c) 2004 Simtec Electronics
- s3c2440-nand s3c2440-nand: Tacls=3, 30ns Twrph0=7 70ns, Twrph1=3 30ns
- NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)
- Scanning device for bad blocks
- Bad eraseblock 482 at 0x03c40000
- Bad eraseblock 1130 at 0x08d40000
- Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit":
- 0x00000000-0x00040000 : "bootloader"
- 0x00040000-0x00060000 : "params"
- 0x00060000-0x00260000 : "kernel"
- 0x00260000-0x10000000 : "root"
- s3c2410-ohci s3c2410-ohci: S3C24XX OHCI
- s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1
- s3c2410-ohci s3c2410-ohci: irq 42, io mem 0x49000000
- usb usb1: configuration #1 chosen from 1 choice
- hub 1-0:1.0: USB hub found
- hub 1-0:1.0: 2 ports detected
- Initializing USB Mass Storage driver...
- usbcore: registered new interface driver usb-storage
- USB Mass Storage support registered.
- mice: PS/2 mouse device common for all mice
- s3c2410 TouchScreen successfully loaded
- input: s3c2410 TouchScreen as /class/input/input0
- S3C24XX RTC, (c) 2004,2006 Simtec Electronics
- s3c2440-i2c s3c2440-i2c: slave address 0x10
- s3c2440-i2c s3c2440-i2c: bus frequency set to 390 KHz
- s3c2440-i2c s3c2440-i2c: i2c-0: S3C I2C adapter
- mapped channel 0 to 0
- s3c2440-sdi s3c2440-sdi: powered down.
- s3c2440-sdi s3c2440-sdi: initialisation done.
- s3c2440-sdi s3c2440-sdi: running at 0kHz (requested: 0kHz).
- s3c2440-sdi s3c2440-sdi: running at 196kHz (requested: 195kHz).
- s3c2440-sdi s3c2440-sdi: running at 196kHz (requested: 195kHz).
- s3c2440-sdi s3c2440-sdi: running at 196kHz (requested: 195kHz).
- usbcore: registered new interface driver hiddev
- s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #2 op:UNKNOWN(8) arg:0x000001aa flags:0x0875 retries:0 Status:nothing to complete
- s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #3 op:APP_CMD(55) arg:0x00000000 flags:0x0875 retries:0 Status:nothing to complete
- usbcore: registered new interface driver usbhid
- drivers/hid/usbhid/hid-core.c: v2.6:USB HID core driver
- Advanced Linux Sound Architecture Driver Version 1.0.14 (Thu May 31 09:03:25 2007 UTC).
- s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #4 op:APP_CMD(55) arg:0x00000000 flags:0x0875 retries:0 Status:nothing to complete
- ASoC version 0.13.1
- s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #5 op:APP_CMD(55) arg:0x00000000 flags:0x0875 retries:0 Status:nothing to complete
- s3c2410iis_probe...
- s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #6 op:APP_CMD(55) arg:0x00000000 flags:0x0875 retries:0 Status:nothing to complete
- s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #7 op:ALL_SEND_OCR(1) arg:0x00000000 flags:0x0861 retries:0 Status:nothing to complete
- s3c2440-sdi s3c2440-sdi: powered down.
- UDA1341 audio driver initialized
- ALSA device list:
- No soundcards found.
- TCP cubic registered
- NET: Registered protocol family 1
- drivers/rtc/hctosys.c: unable to open rtc device (rtc0)
- UDF-fs: No VRS found
- yaffs: dev is 32505859 name is "mtdblock3"
- yaffs: passed flags ""
- yaffs: Attempting MTD mount on 31.3, "mtdblock3"
- yaffs: auto selecting yaffs2
- block 464 is bad
- block 1112 is bad
- VFS: Mounted root (yaffs filesystem).
- Freeing init memory: 140K
- init started: BusyBox v1.7.0 (2008-01-22 10:04:09 EST)
- starting pid 764, tty '': '/etc/init.d/rcS'
- Please press Enter to activate this console. tsdev (compaq touchscreen emulation) is scheduled for removal.
- See Documentation/feature-removal-schedule.txt for details.
- Warning: TimeZone::data Can't create a valid data object for 'Europe/Oslo'
- Warning: could not register server
- starting pid 771, tty '/dev/s3c2410_serial0': '/bin/sh'
- #
- #