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結構的變量,儲存了被引導鏡像的位址大小等資訊。typedef struct _TOC {
DWORD dwSignature;
BYTE udid[8];
// How to boot the images in this TOC.
// This could be moved into the image descriptor if desired,
// but I prefer to conserve space.
BOOT_CFG BootCfg;
// Array of Image Descriptors.
IMAGE_DESCRIPTOR id[MAX_TOC_DESCRIPTORS];
CHAININFO chainInfo;
} 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的啟動資訊。#define BAUD_RATE 38400
void Uart_Init(void)
{
int i;
rUFCON1 = 0x0; // FIFO disable
rUMCON1 = 0x0; // AFC disable
rULCON1 = 0x3; // Normal,No parity,1 stop,8 bits
rUCON1 = 0x245;
rUBRDIV1=( (int)(PCLK/16./BAUD_RATE) -1 );
for(i=0;i<100;i++);
}
其他的初始化部分我參考我的資源中的工程
(4)ReadEbootFromNand函數
ReadEbootFromNand這個函數是這個工程中的核心,用來讀取NandFlash起始位置為Block 2的Eboot到指定的SDRAM位址中,然後跳轉到Eboot運作。
幾個重要的參數為
#define EBOOT_RAM_IMAGE_SIZE 0x00040000 //256K Eboot
#define EBOOT_BLOCK 2 //Eboot起始Block
#define EBOOT_RAM_IMAGE_BASE 0x8c038000 //Eboot在SDRAM的位址
DWORD ReadEbootFromNand()
{
DWORD dwSectorsNeeded;
DWORD dwSector, dwLength; // Start Sector & Length
DWORD dwRAM, i;
//Init Toc
toc.id[0].dwVersion = (EBOOT_VERSION_MAJOR << 16) | EBOOT_VERSION_MINOR;
toc.id[0].dwSignature = IMAGE_EBOOT_SIG;
toc.id[0].dwImageType = IMAGE_TYPE_RAMIMAGE;
//以上三個參數其實實際并未用到
toc.id[0].dwLoadAddress = EBOOT_RAM_IMAGE_BASE;//Eboot在SDRAM的位址
toc.id[0].dwJumpAddress = EBOOT_RAM_IMAGE_BASE;
toc.id[0].dwTtlSectors = FILE_TO_SECTOR_SIZE(EBOOT_RAM_IMAGE_SIZE);//Eboot所占Sectors數目
// 1 contigious segment
toc.id[0].sgList[0].dwSector = BLOCK_TO_SECTOR(EBOOT_BLOCK);//計算Eboot起始Sector
toc.id[0].sgList[0].dwLength = toc.id[0].dwTtlSectors;//傳遞Sectors數
dwSectorsNeeded = toc.id[0].dwTtlSectors;
dwRAM = VIRTUAL_TO_PHYSICAL(toc.id[0].dwLoadAddress);//計算Eboot在RAM中的實體位址
JumpAddr = toc.id[0].dwJumpAddress ? VIRTUAL_TO_PHYSICAL(toc.id[0].dwJumpAddress) :
VIRTUAL_TO_PHYSICAL(toc.id[0].dwLoadAddress);//Eboot複制完成後的跳轉位址
i = 0;
//從NandFlash Block 2開始複制Eboot到SDRAM中
while (dwSectorsNeeded && i < MAX_SG_SECTORS)
{
dwSector = toc.id[0].sgList[i].dwSector;
dwLength = toc.id[0].sgList[i].dwLength;
// read each sg segment
while (dwLength) {
if ( !FMD_ReadSector(dwSector, (LPBYTE)dwRAM, NULL, 1) )
{
// Uart_SendString("ERR_DISK_OP_FAIL2: ");
// Uart_SendDWORD(dwSector, TRUE);
}
dwSector++;
dwLength--;
dwRAM += SECTOR_SIZE;
}
dwSectorsNeeded -= toc.id[0].sgList[i].dwLength;
i++;
}
return ERR_SUCCESS;
}
(5)啟動Eboot
通過調用Launch(JumpAddr)函數跳轉到Eboot
Launch是用彙編寫的,Eboot中也會調用這個函數來跳轉到核心
EXPORT Launch
Launch
nop
nop
nop
nop
mov pc, r0 ; Jump to PhysicalAddress
nop
MOV_PC_LR
END
(6)Main
void Main(void)
{
DWORD err;
MMU_EnableICache();
Uart_Init();
Uart_SendString(SIGN_ON);
NF_Init();
ReadEbootFromNand();
Launch(JumpAddr);
Uart_SendString("/nBoot ERROR:");
Uart_SendDWORD(err, TRUE);
while (1);
}
(7)超級終端中的顯示結果,關于Eboot的移植将在後文中闡述