S3C2440学习之自己写bootloader

最简单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 跳转执行内核
2.首先写start.S,主要内容如下:
/* 1. 关看门狗 */
[cpp]  view plain  copy
 print ?
  1. ldr r0, =0x53000000  
  2. mov r1, #0  
  3. str r1, [r0]  

/* 2. 设置时钟 */
[cpp]  view plain  copy
 print ?
  1. <span style="white-space:pre">  </span>ldr r0, =0x4c000014  
  2.     mov r1, #0x03;            // FCLK:HCLK:PCLK=1:2:4, HDIVN=1,PDIVN=1  
  3.     str r1, [r0]  
  4.   
  5.     /* 如果HDIVN非0,CPU的总线模式应该从“fast bus mode”变为“asynchronous bus mode” */  
  6.     mrc p15, 0, r1, c1, c0, 0       /* 读出控制寄存器 */   
  7.     orr r1, r1, #0xc0000000         /* 设置为“asynchronous bus mode” */  
  8.     mcr p15, 0, r1, c1, c0, 0       /* 写入控制寄存器 */  
  9.   
  10.     /* MPLLCON = S3C2440_MPLL_200MHZ */  
  11.     ldr r0, =0x4c000004  
  12.     ldr r1, =S3C2440_MPLL_200MHZ  
  13.     str r1, [r0]  
  14.   
  15. <span style="white-space:pre">  </span>#define S3C2440_MPLL_200MHZ     ((0x5c<<12)|(0x01<<4)|(0x02))  
  16. <span style="white-space:pre">  </span>#define MEM_CTL_BASE    0x48000000  
/* 3. 初始化SDRAM */
[cpp]  view plain  copy
 print ?
  1.     ldr r0, =MEM_CTL_BASE  
  2.     adr r1, sdram_config     /* sdram_config的当前地址 */  
  3.     add r3, r0, #(13*4)  
  4. 1:  
  5.     ldr r2, [r1], #4  
  6.     str r2, [r0], #4  
  7.     cmp r0, r3  
  8.     bne 1b  
  9. sdram_config:  
  10.     .long 0x22011110     //BWSCON  
  11.     .long 0x00000700     //BANKCON0  
  12.     .long 0x00000700     //BANKCON1  
  13.     .long 0x00000700     //BANKCON2  
  14.     .long 0x00000700     //BANKCON3    
  15.     .long 0x00000700     //BANKCON4  
  16.     .long 0x00000700     //BANKCON5  
  17.     .long 0x00018005     //BANKCON6  
  18.     .long 0x00018005     //BANKCON7  
  19.     .long 0x008C04F4     //REFRESH  
  20.     .long 0x000000B1     //BANKSIZE  
  21.     .long 0x00000030     //MRSRB6  
  22.     .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.....
[cpp]  view plain  copy
 print ?
  1. void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)  
  2. {     
  3.     int i = 0;  
  4.     /* 如果是NOR启动 */  
  5.     if (isBootFromNorFlash())  
  6.     {  
  7.         while (i < len)  
  8.         {  
  9.             dest[i] = src[i];  
  10.             i++;  
  11.         }  
  12.     }  
  13.     else  
  14.     {  
  15.         //nand_init();  
  16.         nand_read((unsigned int)src, dest, len);  
  17.     }  
  18. }  
需要判断是从哪启动。
[cpp]  view plain  copy
 print ?
  1. int isBootFromNorFlash(void)  
  2. {  
  3.     volatile int *p = (volatile int *)0;  
  4.     int val;  
  5.   
  6.     val = *p;  
  7.     *p = 0x12345678;  
  8.     if (*p == 0x12345678)  
  9.     {  
  10.         /* 写成功, 是nand启动 */  
  11.         *p = val;  
  12.         return 0;  
  13.     }  
  14.     else  
  15.     {  
  16.         /* NOR不能像内存一样写 */  
  17.         return 1;  
  18.     }  
  19. }  
拷贝函数:
[cpp]  view plain  copy
 print ?
  1. void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)  
  2. {     
  3.     int i = 0;  
  4.       
  5.     /* 如果是NOR启动 */  
  6.     if (isBootFromNorFlash())  
  7.     {  
  8.         while (i < len)  
  9.         {  
  10.             dest[i] = src[i];//从原地址读出一个值给目的地址  
  11.             i++;  
  12.         }  
  13.     }  
  14.     else  
  15.     {  
  16.         //nand_init();  
  17.         nand_read((unsigned int)src, dest, len);  
  18.     }  
  19. }  
第一个参数起始地址:r0:0
第二个参数链接地址:r1:链接地址 _start=0X33f80000
第三个参数长度:r2:__bss_start - _start(参考链接脚本)0X33f80000开始存放
如下:

[cpp]  view plain  copy
 print ?
  1. ldr sp, =0x34000000  
  2.   
  3. bl nand_init  
  4.   
  5. mov r0, #0  
  6. ldr r1, =_start  
  7. ldr r2, =__bss_start  
  8. sub r2, r2, r1  
  9.   
  10. bl copy_code_to_sdram  
  11. bl clear_bss  
清除bss段:
bl clear_bss:(init.c中)
[cpp]  view plain  copy
 print ?
  1. void clear_bss(void)  
  2. {  
  3.     extern int __bss_start, __bss_end;  
  4.     int *p = &__bss_start;  
  5.       
  6.     for (; p < &__bss_end; p++)  
  7.         *p = 0;  
  8. }  
接下来写nand_init和 nand_read函数:(内核也存在此处所以肯定需要初始化)...
参考2440手册和nand flash 手册,进行nand的初始化和复制:总的程序:
[cpp]  view plain  copy
 print ?
  1. /* 4. 重定位 : 把bootloader本身的代码从flash复制到它的链接地址去 */  
  2.     ldr sp, =0x34000000  
  3.   
  4.     bl nand_init  
  5.   
  6.     mov r0, #0  
  7.     ldr r1, =_start  
  8.     ldr r2, =__bss_start  
  9.     sub r2, r2, r1  
  10.       
  11.     bl copy_code_to_sdram  
  12.     bl clear_bss  

/* 5. 执行main */
[cpp]  view plain  copy
 print ?
  1.     ldr lr, =halt  
  2.     ldr pc, =main  
  3. halt:  
  4.     b halt  

二.编写第2阶段

写main函数(board.C)
/* 0. 帮内核设置串口: 内核启动的开始部分会从串口打印一些信息,但是内核一开始没有初始化串口所以要完成初始化串口不然后内核启动的时候可能出错 */
[cpp]  view plain  copy
 print ?
  1. uart0_init();  
/* 1. 从NAND FLASH里把内核读入内存 */
0x60000+64(64K的头部)
内核地址0x30008000(内核中配置好的地址)nand_read的实现
[cpp]  view plain  copy
 print ?
  1. <span style="white-space:pre">  </span>/* 1. 从NAND FLASH里把内核读入内存 */  
  2. <span style="white-space:pre">  </span>puts("Copy kernel from nand\n\r");  
  3. <span style="white-space:pre">  </span>nand_read(0x60000+64, (unsigned char *)0x30008000, 0x200000);  
  4. <span style="white-space:pre">  </span>puthex(0x1234ABCD);  
  5. <span style="white-space:pre">  </span>puts("\n\r");  
  6. <span style="white-space:pre">  </span>puthex(*p);  
  7. <span style="white-space:pre">  </span>puts("\n\r");  

/* 2. 设置参数 */

内核和UBOOT约定好在某个地址存放启动参数,比如此处是0x30000100开始存放启动参数,uboot将参数存放到0x30000100开始的地方,内核启动时会从这里取出参数。实现代码如下:
下面几个函数,都向地址内写入了
(1)参数代号
(2)本参数所占内存大小
(3)参数内容
(4)每个参数设置最后都指向了下一参数设置地址
[cpp]  view plain  copy
 print ?
  1. puts("Set boot params\n\r");  
  2. setup_start_tag();  
  3. setup_memory_tags();  
  4. setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");  
  5. setup_end_tag();  

/* 3. 跳转执行,启动内核 */
[cpp]  view plain  copy
 print ?
  1. puts("Boot kernel\n\r");  
  2. theKernel = (void (*)(intint, unsigned int))0x30008000;  
  3. theKernel(0, 362, 0x30000100);    
  4. /*  
  5.  *  mov r0, #0 
  6.  *  ldr r1, =362 
  7.  *  ldr r2, =0x30000100 
  8.  *  mov pc, #0x30008000  
  9.  */  
  10.   
  11. puts("Error!\n\r");  
  12. /* 如果一切正常, 不会执行到这里 */  
  13.   
  14. return -1;  
三、启动LOG
[cpp]  view plain  copy
 print ?
  1. Copy kernel from nand  
  2. 0x1234ABCD  
  3. 0xE1A00000  
  4. Set boot params  
  5. Boot kernel  
  6. Uncompressing Linux...................................................................................................................... done, booting the kernel.  
  7. Linux version 2.6.22.6 (book@book-desktop) (gcc version 3.4.5) #1 Fri Aug 23 15:33:35 CST 2013  
  8. CPU: ARM920T [41129200] revision 0 (ARMv4T), cr=c0007177  
  9. Machine: SMDK2440  
  10. Memory policy: ECC disabled, Data cache writeback  
  11. CPU S3C2440A (id 0x32440001)  
  12. S3C244X: core 200.000 MHz, memory 100.000 MHz, peripheral 50.000 MHz  
  13. S3C24XX Clocks, (c) 2004 Simtec Electronics  
  14. CLOCK: Slow mode (1.500 MHz), fast, MPLL on, UPLL on  
  15. CPU0: D VIVT write-back cache  
  16. CPU0: I cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets  
  17. CPU0: D cache: 16384 bytes, associativity 64, 32 byte lines, 8 sets  
  18. Built 1 zonelists.  Total pages: 16256  
  19. Kernel command line: noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0  
  20. irq: clearing subpending status 00000002  
  21. PID hash table entries: 256 (order: 8, 1024 bytes)  
  22. timer tcon=00000000, tcnt a2c1, tcfg 00000200,00000000, usec 00001eb8  
  23. Console: colour dummy device 80x30  
  24. Dentry cache hash table entries: 8192 (order: 3, 32768 bytes)  
  25. Inode-cache hash table entries: 4096 (order: 2, 16384 bytes)  
  26. Memory: 64MB = 64MB total  
  27. Memory: 60976KB available (3264K code, 458K data, 140K init)  
  28. Mount-cache hash table entries: 512  
  29. CPU: Testing write buffer coherency: ok  
  30. NET: Registered protocol family 16  
  31. S3C2410 Power Management, (c) 2004 Simtec Electronics  
  32. S3C2440: Initialising architecture  
  33. S3C2440: IRQ Support  
  34. S3C2440: Clock Support, DVS off  
  35. S3C24XX DMA Driver, (c) 2003-2004,2006 Simtec Electronics  
  36. DMA channel 0 at c4800000, irq 33  
  37. DMA channel 1 at c4800040, irq 34  
  38. DMA channel 2 at c4800080, irq 35  
  39. DMA channel 3 at c48000c0, irq 36  
  40. SCSI subsystem initialized  
  41. usbcore: registered new interface driver usbfs  
  42. usbcore: registered new interface driver hub  
  43. usbcore: registered new device driver usb  
  44. NET: Registered protocol family 2  
  45. IP route cache hash table entries: 1024 (order: 0, 4096 bytes)  
  46. TCP established hash table entries: 2048 (order: 2, 16384 bytes)  
  47. TCP bind hash table entries: 2048 (order: 1, 8192 bytes)  
  48. TCP: Hash tables configured (established 2048 bind 2048)  
  49. TCP reno registered  
  50. NetWinder Floating Point Emulator V0.97 (double precision)  
  51. Registering GDB sysrq handler  
  52. JFFS2 version 2.2. (NAND) 漏 2001-2006 Red Hat, Inc.  
  53. yaffs Aug 23 2013 15:33:07 Installing.   
  54. io scheduler noop registered  
  55. io scheduler anticipatory registered (default)  
  56. io scheduler deadline registered  
  57. io scheduler cfq registered  
  58. Console: switching to colour frame buffer device 60x34  
  59. fb0: s3c2410fb frame buffer device  
  60. lp: driver loaded but no devices found  
  61. ppdev: user-space parallel port driver  
  62. S3C2410 Watchdog Timer, (c) 2004 Simtec Electronics  
  63. Serial: 8250/16550 driver $Revision: 1.90 $ 4 ports, IRQ sharing enabled  
  64. s3c2440-uart.0: s3c2410_serial0 at MMIO map 0x50000000 mem 0xf0400000 (irq = 70) is a S3C2440  
  65. s3c2440-uart.1: s3c2410_serial1 at MMIO map 0x50004000 mem 0xf0404000 (irq = 73) is a S3C2440  
  66. s3c2440-uart.2: s3c2410_serial2 at MMIO map 0x50008000 mem 0xf0408000 (irq = 76) is a S3C2440  
  67. RAMDISK driver initialized: 16 RAM disks of 4096K size 1024 blocksize  
  68. loop: module loaded  
  69. line 400 <DM9KS> I/O: c486a000, VID: 90000a46   
  70. line 408 <DM9KS> I/O: c486a000, VID: 90000a46   
  71. <DM9KS> error version, chip_revision = 0x19, chip_info = 0x0  
  72. id_val=0  
  73. S3C24XX NAND Driver, (c) 2004 Simtec Electronics  
  74. s3c2440-nand s3c2440-nand: Tacls=3, 30ns Twrph0=7 70ns, Twrph1=3 30ns  
  75. NAND device: Manufacturer ID: 0xec, Chip ID: 0xda (Samsung NAND 256MiB 3,3V 8-bit)  
  76. Scanning device for bad blocks  
  77. Bad eraseblock 482 at 0x03c40000  
  78. Bad eraseblock 1130 at 0x08d40000  
  79. Creating 4 MTD partitions on "NAND 256MiB 3,3V 8-bit":  
  80. 0x00000000-0x00040000 : "bootloader"  
  81. 0x00040000-0x00060000 : "params"  
  82. 0x00060000-0x00260000 : "kernel"  
  83. 0x00260000-0x10000000 : "root"  
  84. s3c2410-ohci s3c2410-ohci: S3C24XX OHCI  
  85. s3c2410-ohci s3c2410-ohci: new USB bus registered, assigned bus number 1  
  86. s3c2410-ohci s3c2410-ohci: irq 42, io mem 0x49000000  
  87. usb usb1: configuration #1 chosen from 1 choice  
  88. hub 1-0:1.0: USB hub found  
  89. hub 1-0:1.0: 2 ports detected  
  90. Initializing USB Mass Storage driver...  
  91. usbcore: registered new interface driver usb-storage  
  92. USB Mass Storage support registered.  
  93. mice: PS/2 mouse device common for all mice  
  94. s3c2410 TouchScreen successfully loaded  
  95. input: s3c2410 TouchScreen as /class/input/input0  
  96. S3C24XX RTC, (c) 2004,2006 Simtec Electronics  
  97. s3c2440-i2c s3c2440-i2c: slave address 0x10  
  98. s3c2440-i2c s3c2440-i2c: bus frequency set to 390 KHz  
  99. s3c2440-i2c s3c2440-i2c: i2c-0: S3C I2C adapter  
  100. mapped channel 0 to 0  
  101. s3c2440-sdi s3c2440-sdi: powered down.  
  102. s3c2440-sdi s3c2440-sdi: initialisation done.  
  103. s3c2440-sdi s3c2440-sdi: running at 0kHz (requested: 0kHz).  
  104. s3c2440-sdi s3c2440-sdi: running at 196kHz (requested: 195kHz).  
  105. s3c2440-sdi s3c2440-sdi: running at 196kHz (requested: 195kHz).  
  106. s3c2440-sdi s3c2440-sdi: running at 196kHz (requested: 195kHz).  
  107. usbcore: registered new interface driver hiddev  
  108. s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #2 op:UNKNOWN(8) arg:0x000001aa flags:0x0875 retries:0 Status:nothing to complete  
  109. s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #3 op:APP_CMD(55) arg:0x00000000 flags:0x0875 retries:0 Status:nothing to complete  
  110. usbcore: registered new interface driver usbhid  
  111. drivers/hid/usbhid/hid-core.c: v2.6:USB HID core driver  
  112. Advanced Linux Sound Architecture Driver Version 1.0.14 (Thu May 31 09:03:25 2007 UTC).  
  113. s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #4 op:APP_CMD(55) arg:0x00000000 flags:0x0875 retries:0 Status:nothing to complete  
  114. ASoC version 0.13.1  
  115. s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #5 op:APP_CMD(55) arg:0x00000000 flags:0x0875 retries:0 Status:nothing to complete  
  116. s3c2410iis_probe...  
  117. s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #6 op:APP_CMD(55) arg:0x00000000 flags:0x0875 retries:0 Status:nothing to complete  
  118. s3c2440-sdi s3c2440-sdi: CMD[TIMEOUT] #7 op:ALL_SEND_OCR(1) arg:0x00000000 flags:0x0861 retries:0 Status:nothing to complete  
  119. s3c2440-sdi s3c2440-sdi: powered down.  
  120. UDA1341 audio driver initialized  
  121. ALSA device list:  
  122.   No soundcards found.  
  123. TCP cubic registered  
  124. NET: Registered protocol family 1  
  125. drivers/rtc/hctosys.c: unable to open rtc device (rtc0)  
  126. UDF-fs: No VRS found  
  127. yaffs: dev is 32505859 name is "mtdblock3"  
  128. yaffs: passed flags ""  
  129. yaffs: Attempting MTD mount on 31.3, "mtdblock3"  
  130. yaffs: auto selecting yaffs2  
  131. block 464 is bad  
  132. block 1112 is bad  
  133. VFS: Mounted root (yaffs filesystem).  
  134. Freeing init memory: 140K  
  135. init started: BusyBox v1.7.0 (2008-01-22 10:04:09 EST)  
  136. starting pid 764, tty '''/etc/init.d/rcS'  
  137.   
  138. Please press Enter to activate this console. tsdev (compaq touchscreen emulation) is scheduled for removal.  
  139. See Documentation/feature-removal-schedule.txt for details.  
  140. Warning: TimeZone::data Can't create a valid data object for 'Europe/Oslo'  
  141. Warning: could not register server  
  142.   
  143. starting pid 771, tty '/dev/s3c2410_serial0''/bin/sh'  
  144.   
  145. #  

猜你喜欢

转载自blog.csdn.net/weixin_38807927/article/details/77572248