GEC2410开发板自带的Eboot需要通过自带的Bootloader下载后才能运行,这个Eboot只起到下载内核镜像的作用,重启后是通过Nboot启动内核而不是Eboot。而且也不支持KITL,BSP的结构也完全是4.2下的,非常凌乱。不知道开发板商为什么不能按照5.0的架构做一个支持KITL内核调试的Eboot。
因此产生了移植一个上电后能直接运行的Eboot的想法。由于S3C2410支持4K的Steppintstone,可以从Nand Flash启动,我把Eboot放在Nand Flash中,用Nboot进行引导。NBoot位于NandFlash的Block 0,Eboot位于Block 2。上电后,位于前4K的Nboot被复制到RAM中运行,然后Nboot复制Eboot到RAM中,最后跳转到Eboot,由Eboot进行下一步的工作。
或者把Eboot放到Nor Flash中,也不需要Nboot,之后将介绍基于Nor Flash的移植
整个工程位于:http://download.csdn.net/source/620556中的NBoot_2410(Eboot)目录下。
一、开发环境
编译器: ADS1.2
目标板: GEC2410 S3C2410A,NAND Flash:64M K9F1208,NOR Flash:2M SST39VF1601 SDRAM 64M,CS8900
二、开始移植
(1)一般Nboot的结构
板子自带的Nboot是用来直接引导CE内核的,它需要一个toc结构的变量,保存了被引导镜像的地址大小等信息。
2 DWORD dwSignature;
3 BYTE udid[ 8 ];
4 // How to boot the images in this TOC.
5 // This could be moved into the image descriptor if desired,
6 // but I prefer to conserve space.
7 BOOT_CFG BootCfg;
8
9 // Array of Image Descriptors.
10 IMAGE_DESCRIPTOR id[MAX_TOC_DESCRIPTORS];
11
12 CHAININFO chainInfo;
13 } TOC, * PTOC; // 512 bytes
开发板自带的Eoot被下载后将在Block 1写入这个toc结构,然后Nboot在读取信息来引导CE Image。
同理如果用来启动Eboot,只需要把Eboot的信息写入这个结构即可。我们不把toc放入Block 1然后再去读,而是直接在程序中定义好,因为Eboot大小位置都是固定的。
(2)修改Nboot
我在网上找到一个最近似我需求的Nboot,已经把toc结构成员进行了初始化,只需要修改相应的参数即可。
(3)串口驱动
我使用UART1 38400kbps,用来输出Nboot的启动信息。
2
3 void Uart_Init( void )
4 {
5 int i;
6
7 rUFCON1 = 0x0 ; // FIFO disable
8 rUMCON1 = 0x0 ; // AFC disable
9 rULCON1 = 0x3 ; // Normal,No parity,1 stop,8 bits
10 rUCON1 = 0x245 ;
11 rUBRDIV1 = ( ( int )(PCLK / 16 . / BAUD_RATE) - 1 );
12 for (i = 0 ;i < 100 ;i ++ );
13 }
其他的初始化部分我参考我的资源中的工程
(4)ReadEbootFromNand函数
ReadEbootFromNand这个函数是这个工程中的核心,用来读取NandFlash起始位置为Block 2的Eboot到指定的SDRAM地址中,然后跳转到Eboot运行。
几个重要的参数为:
2 #define EBOOT_BLOCK 2 // Eboot起始Block
3 #define EBOOT_RAM_IMAGE_BASE 0x8c038000 // Eboot在SDRAM的地址
4
5 DWORD ReadEbootFromNand()
6 {
7 DWORD dwSectorsNeeded;
8 DWORD dwSector, dwLength; // Start Sector & Length
9 DWORD dwRAM, i;
10
11 // Init Toc
12 toc.id[ 0 ].dwVersion = (EBOOT_VERSION_MAJOR << 16 ) | EBOOT_VERSION_MINOR;
13 toc.id[ 0 ].dwSignature = IMAGE_EBOOT_SIG;
14 toc.id[ 0 ].dwImageType = IMAGE_TYPE_RAMIMAGE;
15 // 以上三个参数其实实际并未用到
16 toc.id[ 0 ].dwLoadAddress = EBOOT_RAM_IMAGE_BASE; // Eboot在SDRAM的地址
17 toc.id[ 0 ].dwJumpAddress = EBOOT_RAM_IMAGE_BASE;
18 toc.id[ 0 ].dwTtlSectors = FILE_TO_SECTOR_SIZE(EBOOT_RAM_IMAGE_SIZE); // Eboot所占Sectors数目
19 // 1 contigious segment
20 toc.id[ 0 ].sgList[ 0 ].dwSector = BLOCK_TO_SECTOR(EBOOT_BLOCK); // 计算Eboot起始Sector
21 toc.id[ 0 ].sgList[ 0 ].dwLength = toc.id[ 0 ].dwTtlSectors; // 传递Sectors数
22 dwSectorsNeeded = toc.id[ 0 ].dwTtlSectors;
23
24 dwRAM = VIRTUAL_TO_PHYSICAL(toc.id[ 0 ].dwLoadAddress); // 计算Eboot在RAM中的物理地址
25 JumpAddr = toc.id[ 0 ].dwJumpAddress ? VIRTUAL_TO_PHYSICAL(toc.id[ 0 ].dwJumpAddress) :
26 VIRTUAL_TO_PHYSICAL(toc.id[ 0 ].dwLoadAddress); // Eboot复制完成后的跳转地址
27
28 i = 0 ;
29 // 从NandFlash Block 2开始复制Eboot到SDRAM中
30 while (dwSectorsNeeded && i < MAX_SG_SECTORS)
31 {
32 dwSector = toc.id[ 0 ].sgList[i].dwSector;
33 dwLength = toc.id[ 0 ].sgList[i].dwLength;
34 // read each sg segment
35 while (dwLength) {
36 if ( ! FMD_ReadSector(dwSector, (LPBYTE)dwRAM, NULL, 1 ) )
37 {
38 // Uart_SendString("ERR_DISK_OP_FAIL2: ");
39 // Uart_SendDWORD(dwSector, TRUE);
40 }
41 dwSector ++ ;
42 dwLength -- ;
43 dwRAM += SECTOR_SIZE;
44 }
45 dwSectorsNeeded -= toc.id[ 0 ].sgList[i].dwLength;
46 i ++ ;
47 }
48 return ERR_SUCCESS;
49 }
(5)启动Eboot
通过调用Launch(JumpAddr)函数跳转到Eboot
Launch是用汇编写的,Eboot中也会调用这个函数来跳转到内核
2 Launch
3 nop
4 nop
5 nop
6 nop
7
8 mov pc, r0 ; Jump to PhysicalAddress
9 nop
10 MOV_PC_LR
11
12 END
(6)Main
2 {
3 DWORD err;
4
5 MMU_EnableICache();
6 Uart_Init();
7 Uart_SendString(SIGN_ON);
8 NF_Init();
9 ReadEbootFromNand();
10 Launch(JumpAddr);
11 Uart_SendString( " \nBoot ERROR: " );
12 Uart_SendDWORD(err, TRUE);
13 while ( 1 );
14 }
(7)超级终端中的显示结果,关于Eboot的移植将在后文中阐述