bootloader的作用有两个,一是初始化软硬件,二是启动操作系统。bootm命令是从内存中运行某一程序,通常用该命令来启动操作系统。比如通过tftp下载内核到内存0x31000000处,可通过执行指令bootm 31000000启动内核。
ps:内核文件有两个:zImage和uImage,zImage是纯粹的内核程序,uImage则在zImage的基础上添加了信息头,一般来说bootm命令使用的是uImage。
bootm命令所完成的工作如下:
为了简单,这里省去了检查信息头这步骤,因此可采用zImage。
源文件为:
#include "atag.h"
#include "string.h"
#define SDRAM_KERNEL_START 0x31000000
#define SDRAM_TAGS_START 0x30000100
#define SDRAM_ADDR_START 0x30000000
#define SDRAM_TOTAL_SIZE 0x04000000
void (*theKernel)(int , int , unsigned int );/*定义了一个函数指针*/
struct tag *pCurTag;
const char *cmdline = "console=ttySAC0,115200 init=/init";/*这是Linux内核需要的命令行*/
void setup_core_tag()
{
pCurTag = (struct tag *)SDRAM_TAGS_START;
pCurTag->hdr.tag = ATAG_CORE;
pCurTag->hdr.size = tag_size(tag_core);
pCurTag->u.core.flags = 0;
pCurTag->u.core.pagesize = 4096;
pCurTag->u.core.rootdev = 0;
pCurTag = tag_next(pCurTag);
}
void setup_mem_tag()
{
pCurTag->hdr.tag = ATAG_MEM;
pCurTag->hdr.size = tag_size(tag_mem32);
pCurTag->u.mem.start = SDRAM_ADDR_START;
pCurTag->u.mem.size = SDRAM_TOTAL_SIZE;
pCurTag = tag_next(pCurTag);
}
void setup_cmdline_tag()
{
int linelen = strlen(cmdline);
pCurTag->hdr.tag = ATAG_CMDLINE;
pCurTag->hdr.size = (sizeof(struct tag_header)+linelen+1+4)>>2;
strcpy(pCurTag->u.cmdline.cmdline,cmdline);
pCurTag = tag_next(pCurTag);
}
void setup_end_tag()
{
pCurTag->hdr.tag = ATAG_NONE;
pCurTag->hdr.size = 0;
}
void boot_linux()
{
//1. 获取Linux启动地址
theKernel = (void (*)(int , int , unsigned int ))SDRAM_KERNEL_START;
/*将SDRAM_KERNEL_START强制转换为(void (*)(int , int , unsigned int ))类型指针,然后对函数指针进行赋值*/
//2. 设置启动参数
//2.1 设置核心启动参数
setup_core_tag();
//2.2 设置内存参数
setup_mem_tag();
//2.3 设置命令行参数
setup_cmdline_tag();
//2.4 设置参数结束标志
setup_end_tag();
//3. 启动Linux系统
theKernel(0,168,SDRAM_TAGS_START);/*调用函数,这是函数指针的用法*/
/*内核接受三个参数,第一个为0,第二个为处理器编号,第三个为启动参数的地址*/
}
头文件为:
#define ATAG_CORE 0x54410001
#define ATAG_MEM 0x54410002
#define ATAG_CMDLINE 0x54410009
#define ATAG_NONE 0x00000000
struct tag_header {
unsigned int size;
unsigned int tag;
};
struct tag_core {
unsigned int flags;
unsigned int pagesize;
unsigned int rootdev;
};
struct tag_mem32 {
unsigned int size;
unsigned int start;
};
struct tag_cmdline {
char cmdline[1];
};
struct tag {
struct tag_header hdr;
union {
struct tag_core core;
struct tag_mem32 mem;
struct tag_cmdline cmdline;
} u;
};
#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
#define tag_next(t) ((struct tag *)((unsigned int *)(t) + (t)->hdr.size))
ps:启动Linux内核时,若内核启动一部分后停止,则问题很可能是写错了处理器编号。代码theKernel(0,168,SDRAM_TAGS_START)中的168为处理器S3C2440的编号。启动程序中的处理器编号会作为参数传递给内核,而内核中也存在着一个处理器编号序列,两者必须一样才能正常启动内核。