1 对BOARD的抽象
Linux里用struct machine_desc来抽象板级支持。该结构描述了一个板子的基本硬件信息及函数。
struct machine_desc {
/*
* Note! The first four elements are used
* by assembler code in head.S, head-common.S
*/
//nr是板子的编号,每种类型的板子都有一个唯一的编号,内核根据bootloader送过来的板子编号来查其对应的struct machine_desc。
unsigned int nr; /* architecture number */
unsigned int phys_io; /* start of physical io */
unsigned int io_pg_offst; /* byte offset for io
* page tabe entry */
const char *name; /* architecture name */
unsigned long boot_params; /* tagged list */
unsigned int video_start; /* start of video RAM */
unsigned int video_end; /* end of video RAM */
unsigned int reserve_lp0 :1; /* never has lp0 */
unsigned int reserve_lp1 :1; /* never has lp1 */
unsigned int reserve_lp2 :1; /* never has lp2 */
unsigned int soft_reboot :1; /* soft reboot */
void (*fixup)(struct machine_desc *,
struct tag *, char **,
struct meminfo *);
void (*map_io)(void);/* IO mapping function */
void (*init_irq)(void);
struct sys_timer *timer; /* system tick timer */
void (*init_machine)(void);
};
/*
* Set of macros to define architecture features. This is built into
* a table by the linker.
*/
//内核提供了一个struct machine_desc的构造模板将该结构放入__section__(".arch.info.init"),所以内核对支持哪些board,那么一定会在内存:
__arch_info_begin = .;
*(.arch.info.init)
__arch_info_end = .;
里找到其对应的struct machine_desc。
#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 \
};
//I.MX51的一个Babbage Board实现,对于MX51 Babbage Board,内核提供了
用来映射IO地址空间的函数mx5_map_io,用来初始化中断控制器的函数mx5_init_irq,用来注册外围设备函数mxc_board_init。而对于struct machine_desc没有能够覆盖到的处理函数,可以在fixup函数里处理。
MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board")
/* Maintainer: Freescale Semiconductor, Inc. */
.fixup = fixup_mxc_board,
.map_io = mx5_map_io,
.init_irq = mx5_init_irq,
.init_machine = mxc_board_init,
.timer = &mxc_timer,
MACHINE_END
2 板级抽象结构的查找
arch/arm/kernel/head-common.S中
//从label 3开始的地方存放着struct machine_desc结构列表地址的地址
3: .long .
.long __arch_info_begin
.long __arch_info_end
__lookup_machine_type:
//把label 3的地址放入r3
adr r3, 3b
//r5放入起始地址,r6放入结束地址
ldmia r3, {r4, r5, r6}
sub r3, r3, r4 @ get offset between virt&phys
add r5, r5, r3 @ convert virt addresses to
add r6, r6, r3 @ physical address space
//顺着struct machine_desc结构列表地址逐个查找ID匹配r1的结构
1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
teq r3, r1 @ matches loader number?
beq 2f @ found
add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
cmp r5, r6
blo 1b
mov r5, #0 @ unknown machine
2: mov pc, lr
//如果找到了r5里存放着着struct machine_desc结构地址,否则为0.
ENDPROC(__lookup_machine_type)
/*
* This provides a C-API version of the above function.
*/
ENTRY(lookup_machine_type)
stmfd sp!, {r4 - r6, lr}
//r0里是板子的ID号,将其放到r1中
mov r1, r0
bl __lookup_machine_type
//作为返回结果,把r5放入r0
mov r0, r5
ldmfd sp!, {r4 - r6, pc}
ENDPROC(lookup_machine_type)
Linux里用struct machine_desc来抽象板级支持。该结构描述了一个板子的基本硬件信息及函数。
struct machine_desc {
/*
* Note! The first four elements are used
* by assembler code in head.S, head-common.S
*/
//nr是板子的编号,每种类型的板子都有一个唯一的编号,内核根据bootloader送过来的板子编号来查其对应的struct machine_desc。
unsigned int nr; /* architecture number */
unsigned int phys_io; /* start of physical io */
unsigned int io_pg_offst; /* byte offset for io
* page tabe entry */
const char *name; /* architecture name */
unsigned long boot_params; /* tagged list */
unsigned int video_start; /* start of video RAM */
unsigned int video_end; /* end of video RAM */
unsigned int reserve_lp0 :1; /* never has lp0 */
unsigned int reserve_lp1 :1; /* never has lp1 */
unsigned int reserve_lp2 :1; /* never has lp2 */
unsigned int soft_reboot :1; /* soft reboot */
void (*fixup)(struct machine_desc *,
struct tag *, char **,
struct meminfo *);
void (*map_io)(void);/* IO mapping function */
void (*init_irq)(void);
struct sys_timer *timer; /* system tick timer */
void (*init_machine)(void);
};
/*
* Set of macros to define architecture features. This is built into
* a table by the linker.
*/
//内核提供了一个struct machine_desc的构造模板将该结构放入__section__(".arch.info.init"),所以内核对支持哪些board,那么一定会在内存:
__arch_info_begin = .;
*(.arch.info.init)
__arch_info_end = .;
里找到其对应的struct machine_desc。
#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 \
};
//I.MX51的一个Babbage Board实现,对于MX51 Babbage Board,内核提供了
用来映射IO地址空间的函数mx5_map_io,用来初始化中断控制器的函数mx5_init_irq,用来注册外围设备函数mxc_board_init。而对于struct machine_desc没有能够覆盖到的处理函数,可以在fixup函数里处理。
MACHINE_START(MX51_BABBAGE, "Freescale MX51 Babbage Board")
/* Maintainer: Freescale Semiconductor, Inc. */
.fixup = fixup_mxc_board,
.map_io = mx5_map_io,
.init_irq = mx5_init_irq,
.init_machine = mxc_board_init,
.timer = &mxc_timer,
MACHINE_END
2 板级抽象结构的查找
arch/arm/kernel/head-common.S中
//从label 3开始的地方存放着struct machine_desc结构列表地址的地址
3: .long .
.long __arch_info_begin
.long __arch_info_end
__lookup_machine_type:
//把label 3的地址放入r3
adr r3, 3b
//r5放入起始地址,r6放入结束地址
ldmia r3, {r4, r5, r6}
sub r3, r3, r4 @ get offset between virt&phys
add r5, r5, r3 @ convert virt addresses to
add r6, r6, r3 @ physical address space
//顺着struct machine_desc结构列表地址逐个查找ID匹配r1的结构
1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type
teq r3, r1 @ matches loader number?
beq 2f @ found
add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
cmp r5, r6
blo 1b
mov r5, #0 @ unknown machine
2: mov pc, lr
//如果找到了r5里存放着着struct machine_desc结构地址,否则为0.
ENDPROC(__lookup_machine_type)
/*
* This provides a C-API version of the above function.
*/
ENTRY(lookup_machine_type)
stmfd sp!, {r4 - r6, lr}
//r0里是板子的ID号,将其放到r1中
mov r1, r0
bl __lookup_machine_type
//作为返回结果,把r5放入r0
mov r0, r5
ldmfd sp!, {r4 - r6, pc}
ENDPROC(lookup_machine_type)