1. 程式人生 > >S3C2440學習之自己寫bootloader

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