之前已经写过在main函数中
6.初始化串口
7.读内核到内存
8.设置参数
9.跳转执行
初始化串口
void uart0_init(void)
{
GPHCON |= 0xa0; // GPH2,GPH3用作TXD0,RXD0
GPHUP = 0x0c; // GPH2,GPH3内部上拉
ULCON0 = 0x03; // 8N1(8个数据位,无较验,1个停止位)
UCON0 = 0x05; // 查询方式,UART时钟源为PCLK
UFCON0 = 0x00; // 不使用FIFO
UMCON0 = 0x00; // 不使用流控
UBRDIV0 = UART_BRD; // 波特率为115200
}
初始化串口的函数无非就是设置一些寄存器,参考2440手册
写一个打印字符串的函数,用于调试
void puts(char *str)
{
int i = 0;
while (str[i])
{
putc(str[i]);
i++;
}
}
void putc(unsigned char c)
{
/* 等待,直到发送缓冲区中的数据已经全部发送出去 */
while (!(UTRSTAT0 & TXD0READY));
/* 向UTXH0寄存器中写入数据,UART即自动将它发送出去 */
UTXH0 = c;
}
再写一个打印十六进制数的函数,用于打印某些数值
void puthex(unsigned int val)
{
/* 0x1234abcd */
int i;
int j;
puts("0x");
for (i = 0; i < 8; i++)
{
j = (val >> ((7-i)*4)) & 0xf;
if ((j >= 0) && (j <= 9))
putc('0' + j);
else
putc('A' + j - 0xa);
}
}
读内核到内存
nand_read(0x60000+64, (unsigned char *)0x30008000, 0x200000);
读nand的函数之前写过了
内核存在0x60000处,加上64字节的头部
目的为0x30008000
长度为0x200000
设置参数
bootloader需要传递一些信息给内核,把这些信息放在一个约定的地点,内核运行的时候会从这个地方读
bootloader中有个结构体名为tag,我们设置四个结构体放在约定的地方就可以了
setup_start_tag();
setup_memory_tags();
setup_commandline_tag("noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0");
setup_end_tag();
一个是起始tag
一个是存储内存信息的tag
一个是存储命令行参数的tag
一个是结束tag
void setup_start_tag(void)
{
params = (struct tag *)0x30000100;
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size (tag_core);
params->u.core.flags = 0;
params->u.core.pagesize = 0;
params->u.core.rootdev = 0;
params = tag_next (params);
}
void setup_memory_tags(void)
{
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size (tag_mem32);
params->u.mem.start = 0x30000000;
params->u.mem.size = 64*1024*1024;
params = tag_next (params);
}
int strlen(char *str)
{
int i = 0;
while (str[i])
{
i++;
}
return i;
}
void strcpy(char *dest, char *src)
{
while ((*dest++ = *src++) != '\0');
}
void setup_commandline_tag(char *cmdline)
{
int len = strlen(cmdline) + 1;
params->hdr.tag = ATAG_CMDLINE;
params->hdr.size = (sizeof (struct tag_header) + len + 3) >> 2;
strcpy (params->u.cmdline.cmdline, cmdline);
params = tag_next (params);
}
void setup_end_tag(void)
{
params->hdr.tag = ATAG_NONE;
params->hdr.size = 0;
}
设置完一个tag会把params指向tag_next (params)
跳转执行
void (*theKernel)(int zero, int arch, unsigned int params);
定义一个函数指针
theKernel = (void (*)(int, int, unsigned int))0x30008000;
theKernel(0, 362, 0x30000100);
让函数指针指向一个地址
执行这个函数就会到指定的地址去执行