?? main.c
字號:
/********************************************************************
' 創建日期: 2006/04/18
' 文件名稱: header.h
' 文件作者: GENE.SHAO (E-Mail: sjiang1981@163.com)
'
' 文件功能: 初始化內存控制器,I/O端口,將linux kernel從FLASH讀到內存中,
設置linux啟動參數,然后跳轉到內核的起始地址運行.
' 文件描述: 在使用該文件的時候請確保DOWNLOAD_ADDRESS,MEM_OFFSET,
LINUX_PARAM_OFFSET和你的linux內核中設置的值一致.
該程序在Samsung的s3c2410處理器上測試通過,你可以重新發
布或修改該程序,如果對該程序有何疑問請通過Email聯系作者。
*********************************************************************/
#include "header.h"
///linux參數結構, 是從linux內核中取出來的
/* This is the old deprecated way to pass parameters to the kernel */
struct param_struct {
union {
struct {
unsigned long page_size; /* 0 */
unsigned long nr_pages; /* 4 */
unsigned long ramdisk_size; /* 8 */
unsigned long flags; /* 12 */
#define FLAG_READONLY 1
#define FLAG_RDLOAD 4
#define FLAG_RDPROMPT 8
unsigned long rootdev; /* 16 */
unsigned long video_num_cols; /* 20 */
unsigned long video_num_rows; /* 24 */
unsigned long video_x; /* 28 */
unsigned long video_y; /* 32 */
unsigned long memc_control_reg; /* 36 */
unsigned char sounddefault; /* 40 */
unsigned char adfsdrives; /* 41 */
unsigned char bytes_per_char_h; /* 42 */
unsigned char bytes_per_char_v; /* 43 */
unsigned long pages_in_bank[4]; /* 44 */
unsigned long pages_in_vram; /* 60 */
unsigned long initrd_start; /* 64 */
unsigned long initrd_size; /* 68 */
unsigned long rd_start; /* 72 */
unsigned long system_rev; /* 76 */
unsigned long system_serial_low; /* 80 */
unsigned long system_serial_high; /* 84 */
unsigned long mem_fclk_21285; /* 88 */
} s;
char unused[256];
} u1;
union {
char paths[8][128];
struct {
unsigned long magic;
char n[1024 - sizeof(unsigned long)];
} s;
} u2;
char commandline[1024];
};
//內存控制器初始值
static unsigned long memory_controller_inti_value[] =
{
0x22111120,
0x00000700,
0x00000700,
0x00000700,
0x00000700,
0x00000700,
0x00000700,
0x00018005,
0x00018005,
0x008E0459,
0x000000B2,
0x00000030,
0x00000030,
};
void Delay(int time)
{
int i;
for(i=0;i<1000;i++);
}
//設置led燈, led1-led4, 0表示亮, 1表示滅
void set_led(int led1, int led2, int led3, int led4)
{
(*(volatile char *) GPFDAT) = (led1 << 4) | (led2 << 5) | (led3 << 6) | (led4 << 7);
return;
}
//等待NAND FLASH空閑
inline void wait_idle(void)
{
int i;
while(!(rNFSTAT & BUSY))
for(i=0; i<10; i++);
}
//初始化內存控制器
void init_memory_controller()
{
int i;
for (i=0; i<13; i++)
{
(*(volatile long *) (BWSCON + 4 * i)) = memory_controller_inti_value[i];
}
}
//讀取NAND FLASH, 將start_addr處開始的size個字節讀到buf中.
int read_nand_flash(unsigned char *buf, unsigned long start_addr, int size)
{
int i = 0, j;
//要讀取的FLASH首地址必須是按塊對其的,且讀取的大小為塊的整倍數
if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK))
{
return -1;
}
//啟用FLASH控制器
rNFCONF &= ~0x800;
for(i=0; i<10; i++);
for(i=start_addr; i < (start_addr + size);)
{
//發送讀命令
rNFCMD = 0;
//發送要讀取的地址
rNFADDR = i & 0xff;
rNFADDR = (i >> 9) & 0xff;
rNFADDR = (i >> 17) & 0xff;
rNFADDR = (i >> 25) & 0xff;
wait_idle();
//讀取一個FLASH塊
for(j=0; j < NAND_SECTOR_SIZE; j++, i++)
{
*buf = (rNFDATA & 0xff);
buf++;
}
}
// 禁用FLASH控制器
rNFCONF |= 0x800;
return 0;
}
//初始化UART
void init_uart(int pclk,int baud)
{
int i;
if(pclk == 0)
pclk = PCLK;
rUFCON0 = 0x0;
rUMCON0 = 0x0;
rULCON0 = 0x3;
rUCON0 = 0x245;
rUBRDIV0=( (int)(PCLK/16./115200) -1 );
for(i=0;i<100;i++);
}
//發送一個字節
void uart_send_byte(int data)
{
if(data=='\n')
{
while(!(rUTRSTAT0 & 0x2));
Delay(10); //because the slow response of hyper_terminal
WrUTXH0('\r');
}
while(!(rUTRSTAT0 & 0x2)); //Wait until THR is empty.
Delay(10);
WrUTXH0(data);
}
//一個字符串發送
void uart_send_string(char *pt)
{
while(*pt)
uart_send_byte(*pt++);
}
//重置NAND FLASH
void nand_flash_reset(void)
{
int i;
NF_nFCE_L();
NF_CMD(0xFF);
for(i=0;i<10;i++);
NF_WAITRB();
NF_nFCE_H();
}
//初始化NAND FLASH
void nand_flash_init(void)
{
rNFCONF = 0x0000F830;
nand_flash_reset();
}
//初始化I/O端口和外部中斷
void port_init(void)
{
rGPACON = 0x7fffff;
rGPBUP = 0x7ff;
rGPCCON = 0xaaaaaaaa;
rGPCUP = 0xffff;
rGPDCON = 0xaaaaaaaa;
rGPDUP = 0xffff;
rGPECON = 0xaaaaaaaa;
rGPEUP = 0xffff;
rGPFCON = 0x55aa;
rGPFUP = 0xff;
rGPGCON = 0xff95ffba;
rGPGUP = 0xffff;
rGPHCON = 0x16faaa;
rGPHUP = 0x7ff;
rEXTINT0 = 0x22222222;
rEXTINT1 = 0x22222222;
rEXTINT2 = 0x22222222;
}
//調用linux內核, a0: 0; a1: 處理器類型號; a2: 內核首地址
//關于協處理器15的設置,可參考<<ARM體系結構與編程>>第五章"ARM存儲系統".
void call_linux(long a0, long a1, long a2)
{
__asm__(
"mov r0, %0\n"
"mov r1, %1\n"
"mov r2, %2\n"
"mov ip, #0\n"
"mcr p15, 0, ip, c13, c0, 0\n" //將PID置為0, 禁用快速上下文切換技術
"mcr p15, 0, ip, c7, c7, 0\n" //使I,D caches無效
"mcr p15, 0, ip, c7, c10, 4\n" //清空寫緩沖區
"mcr p15, 0, ip, c8, c7, 0\n" //使I,D快表(TLB)無效
"mrc p15, 0, ip, c1, c0, 0\n" //將寄存器c1中的內容讀到ip(r12)中
"bic ip, ip, #0x0001\n" //清除0位, 禁用MMU
"mcr p15, 0, ip, c1, c0, 0\n" //將ip的內容寫回c1
"mov pc, r2\n" //跳轉到內核的起始地址
"nop\n"
"nop\n"
:
: "r" (a0), "r" (a1), "r" (a2)
);
}
//自己定義的三個函數, 因為這里不能使用庫函數.
//如果使用匯編語言寫,可能效率會高一點. 但是這里只用來拷貝linux啟動參數,足夠用了.
int strlen(char * str)
{
int i;
for (i=0; i<1024; i++) {
if (str[i] == 0) {
return i;
}
}
return 0;
}
void memcpy(char * dst, char * src, int len)
{
int i;
for (i=0; i<len; i++){
*dst++ = *src++;
}
}
void memset(char * dst, unsigned char data, int len)
{
int i;
for (i=0; i<len; i++) {
*dst++ = data;
}
}
//設置linux啟動參數, 我的根文件系統為yaffs文件系統.
static void setup_linux_param(unsigned long param_base)
{
struct param_struct *params = (struct param_struct *)param_base;
char linux_cmd[] = "noinitrd root=/dev/mtdblock/2 init=/linuxrc console=ttyS0";
memset((char *)params, 0, sizeof(struct param_struct));
params->u1.s.page_size = LINUX_PAGE_SIZE;
params->u1.s.nr_pages = (DRAM_SIZE >> LINUX_PAGE_SHIFT);
if (linux_cmd == NULL) {
} else {
memcpy(params->commandline, linux_cmd, strlen(linux_cmd) + 1);
}
}
int main(int argc,char **argv)
{
volatile unsigned char *kernel_start_addr;
//打開第一個LED燈
set_led(0, 1, 1, 1);
init_memory_controller();
port_init();
//打開第二個LED燈
set_led(1, 0, 1, 1);
init_uart(PCLK, 115200);
//打開第三個LED燈
set_led(1, 1, 0, 1);
kernel_start_addr = (unsigned char *)(DOWNLOAD_ADDRESS+MEM_OFFSET);
nand_flash_init();
//打開第四個LED燈
set_led(1, 1, 1, 0);
//打印引導消息
uart_send_string("This bootloader is wrote by ShaoJiang.\n");
uart_send_string("If you have any question about the programme, please email to sjiang1981@163.com.\n");
uart_send_string("Copy linux kernel image from 0x30000 to 0x30008000....\n");
//拷貝linux內核
read_nand_flash(kernel_start_addr, 0x30000, 1024 * 1024);
uart_send_string("Begin to decompress linux kernel.\n");
//設置linux啟動參數
setup_linux_param(DOWNLOAD_ADDRESS+LINUX_PARAM_OFFSET);
//跳轉到linux的起始地址
call_linux(0, 193, DOWNLOAD_ADDRESS+MEM_OFFSET);
return 0;
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -