分类: LINUX
2011-04-06 16:17:01
对于那些常用的处理器,linux内核的移植工作是非常简单的。对于不太常用的处理器,我们只能自己寻求解决方法了。下面以sep4020为例,对此做一些说明。
在linux/arch/arm中有很多mach-xx的文件夹,完成这里的函数编写,就是我们的主要工作,我们把mach-sep4020打开,里面最重要的是一个4020.c文件。在这个文件的最后有MACHINE_START(GFD4020, "4020 board")
.phys_io = 0x10000000,
.io_pg_offst = ((0xe0000000) >> 18) & 0xfffc,
.boot_params = 0x30000100,
.fixup = fixup_gfd4020,
.map_io = sep4020_map_io,
.init_irq = sep4020_init_irq,
.init_machine = sep4020_init,
.timer = &sep4020_timer,
MACHINE_END
这样一段内容,MACHINE_START MACHINE_END是宏定义,在include/asm-arm/mach/arch.h中,可以找到此定义
#define MACHINE_START(_type,_name) \
static const struct machine_desc __mach_desc_##_type \
__used \
__attribute__((__section__(".arch.info.init"))) = { \
.nr = MACH_TYPE_##_type, \
.name = _name,
#define MACHINE_END \
};
从上面的内容,我们可以看出这段宏定义对应了一个machine_desc的结构体,这个结构体的定义如下:
struct machine_desc {
?? unsigned int nr; //电路板序号
?? unsigned int phys_ram; //内存起始物理地址
?? unsigned int phys_io;//io内存物理地址
?? unsigned int io_pg_offst;//io内存页表偏移值
?? const char *name;//设备名称
?? unsigned long boot_params;//bootloader传递参数首物理地址
?? unsigned int video_start;//视频RAM起始地址
?? unsigned int video_end; //视频RAM结束地址
?? unsigned int reserve_lp0 :1;
?? unsigned int reserve_lp1 :1;
?? unsigned int reserve_lp2 :1;//设置的3个打印口
?? unsigned int soft_reboot :1;//软重启
?? void (*fixup)(struct machine_desc *, struct tag *, char **,?? struct meminfo *);??
void (*map_io)(void); //为电路板上所有平台设备建立静态映射页表和各种初始化设置
?? void (*init_irq)(void); //中断初始化
?? struct sys_timer *timer;//系统tick初始化
?? void (*init_machine)(void); //设备初始化一般完成注册平台设备和LED配置以及电源初始化
};
其实我们移植的工作主要就是给上面的这个结构体初始化。我们再来看一下
MACHINE_START(GFD4020, "4020 board")
.phys_io = 0x10000000,
.io_pg_offst = ((0xe0000000) >> 18) & 0xfffc,
.boot_params = 0x30000100,
.fixup = fixup_gfd4020,
.map_io = sep4020_map_io,
.init_irq = sep4020_init_irq,
.init_machine = sep4020_init,
.timer = &sep4020_timer,
MACHINE_END
GFD4020 是mini2440开发板在linux中的机器号。
"4020 board"是开发板信息,在终端输入cat /proc/cpuinfo可以查看。
MACHINE_START主要是定义了"struct machine_desc"的类型,放在 section(".arch.info.init"),是初始化数据,Kernel 起来之后将被丢弃。
其余各个成员函数在setup_arch()中被赋值到内核结构体,在不同时期被调用:
1. .init_machine 在 arch/arm/kernel/setup.c 中被 customize_machine 调用,放在 arch_initcall() 段里面,会自动按顺序被调用。
2. .init_irq在start_kernel() --> init_IRQ() --> init_arch_irq()中被调用
3. .map_io 在 setup_arch() --> paging_init() --> devicemaps_init()中被调用
4. .timer是定义系统时钟,在start_kernel() --> time_init()中被调用。
5. .boot_params是bootloader向内核传递的参数的位置,这要和bootloader中参数的定义要一致。
其他主要都在 setup_arch() 中用到。
通过上面的了解,我们可以发现移植的主要工作是编写machine_desc里面的几个函数,对于sep4020我们主要编写的函数主要有fixup_gfd4020,sep4020_map_io,sep4020_init_irq,
sep4020_init,sep4020_timer等。