***************************************************************************************************************************
作者:EasyWave 时间:2012.02.12
类别:Linux驱动开发 声明:转载,请保留链接
***************************************************************************************************************************
1. phys_io 与 io_pg_offst
我们在移植BSP的时候需要填充 machine_desc 结构体,其中有两个字段 phys_io 和 io_pg_offst,如下红色加粗部分:
MACHINE_START(W90P950EVB, "W90P950EVB")
.phys_io = W90X900_PA_UART,
.io_pg_offst = (((u32)W90X900_VA_UART) >> 18) & 0xfffc,
.boot_params = 0x100,
.map_io = nuc950evb_map_io,
.init_irq = nuc900_init_irq,
.init_machine = nuc950evb_init,
.timer = &nuc900_timer,
MACHINE_END
在linux2.6.38中已经没有phys_io与io_pg_offs这两个变量,后面的文章会分析这个问题,现在就来分析linux2.6.35中在machine_desc结构体中,有关phys_io和io_pg_offst变量的作用以及使用方法,在介绍phys_io和io_pg_offst变量的作用之前,我们先来熟悉一些machine_desc这结构体:
-
struct machine_desc {
-
-
-
-
-
unsigned int nr;
-
unsigned int phys_io;
-
unsigned int io_pg_offst;
-
-
-
const char *name;
-
unsigned long boot_params;
-
-
unsigned int video_start;
-
unsigned int video_end;
-
-
unsigned int reserve_lp0 :1;
-
unsigned int reserve_lp1 :1;
-
unsigned int reserve_lp2 :1;
-
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;
-
void (*init_machine)(void);
-
};
在行7和行8定义了这两个变量,phys_io:物理IO的起始地址,io_pg_offst:IO页表的偏移字节的地址(MMU页表)。phys_io 用来保存 UART 的物理地址,io_pg_offst 用来保存 UART 的内核空间虚拟地址。两者的映射关系在 arch/arm/kernel/head.S 中建立。这样,在 kernel 没有初始化完 MMU 时,就可以通过写 io_pg_offst 向 UART 打印调试信息。这主要在 low level 的调试函数中使用,比如 printascii。
2. phys_io 与 io_pg_offst 的映射关系如何建立
现在可以进入arch\arm\kernel\head.S中分析这两个变量的具体调用情况:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
............
-
............
-
............
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
__HEAD
-
ENTRY(stext)
-
setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
-
@ and irqs disabled
-
mrc p15, 0, r9, c0, c0 @ get processor id
-
bl __lookup_processor_type @ r5=procinfo r9=cpuid
-
movs r10, r5 @ invalid processor (r5=0)?
-
beq __error_p @ yes, error 'p'
-
bl __lookup_machine_type @ r5=machinfo
-
movs r8, r5 @ invalid machine (r5=0)?
-
beq __error_a @ yes, error 'a'
-
bl __vet_atags
-
bl __create_page_tables
-
-
-
-
-
-
-
-
-
ldr r13, __switch_data @ address to jump to after
-
@ mmu has been enabled
-
adr lr, BSYM(__enable_mmu) @ return (PIC) address
-
ARM( add pc, r10, #PROCINFO_INITFUNC )
-
THUMB( add r12, r10, #PROCINFO_INITFUNC )
-
THUMB( mov pc, r12 )
-
ENDPROC(stext)
-
.....
-
.....
-
.....
-
-
-
-
-
-
-
-
-
-
-
-
-
-
__create_page_tables:
-
pgtbl r4 @ page table address
-
-
-
-
-
mov r0, r4
-
mov r3, #0
-
add r6, r0, #0x4000
-
1: str r3, [r0], #4
-
str r3, [r0], #4
-
str r3, [r0], #4
-
str r3, [r0], #4
-
teq r0, r6
-
bne 1b
-
-
ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags
-
-
-
-
-
-
-
-
mov r6, pc
-
mov r6, r6, lsr #20 @ start of kernel section
-
orr r3, r7, r6, lsl #20 @ flags + kernel base
-
str r3, [r4, r6, lsl #2] @ identity mapping
-
-
-
-
-
-
add r0, r4, #(KERNEL_START & 0xff000000) >> 18
-
str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!
-
ldr r6, =(KERNEL_END - 1)
-
add r0, r0, #4
-
add r6, r4, r6, lsr #18
-
1: cmp r0, r6
-
add r3, r3, #1 << 20
-
strls r3, [r0], #4
-
bls 1b
-
-
#ifdef CONFIG_XIP_KERNEL
-
-
-
-
orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000)
-
.if (KERNEL_RAM_PADDR & 0x00f00000)
-
orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000)
-
.endif
-
add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18
-
str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!
-
ldr r6, =(_end - 1)
-
add r0, r0, #4
-
add r6, r4, r6, lsr #18
-
1: cmp r0, r6
-
add r3, r3, #1 << 20
-
strls r3, [r0], #4
-
bls 1b
-
#endif
-
-
-
-
-
add r0, r4, #PAGE_OFFSET >> 18
-
orr r6, r7, #(PHYS_OFFSET & 0xff000000)
-
.if (PHYS_OFFSET & 0x00f00000)
-
orr r6, r6, #(PHYS_OFFSET & 0x00f00000)
-
.endif
-
str r6, [r0]
-
-
#ifdef CONFIG_DEBUG_LL
-
ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
-
-
-
-
-
-
ldr r3, [r8, #MACHINFO_PGOFFIO]
-
add r0, r4, r3
-
rsb r3, r3, #0x4000 @ PTRS_PER_PGD*sizeof(long)
-
cmp r3, #0x0800 @ limit to 512MB
-
movhi r3, #0x0800
-
add r6, r0, r3
-
ldr r3, [r8, #MACHINFO_PHYSIO]
-
orr r3, r3, r7
-
1: str r3, [r0], #4
-
add r3, r3, #1 << 20
-
teq r0, r6
-
bne 1b
-
#if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)
-
-
-
-
-
add r0, r4, #0xff000000 >> 18
-
orr r3, r7, #0x7c000000
-
str r3, [r0]
-
#endif
-
#ifdef CONFIG_ARCH_RPC
-
-
-
-
-
-
add r0, r4, #0x02000000 >> 18
-
orr r3, r7, #0x02000000
-
str r3, [r0]
-
add r0, r4, #0xd8000000 >> 18
-
str r3, [r0]
-
#endif
-
#endif
-
mov pc, lr
-
ENDPROC(__create_page_tables)
在47行中我们可以看到:bl __create_page_tables 就进入到了create_page_tables函数中去了,这个函数在上面的79行,将151行开始的代码拿出来单独分析:
#ifdef CONFIG_DEBUG_LL
ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
/*
* Map in IO space for serial debugging.
* This allows debug messages to be output
* via a serial console before paging_init.
*/
ldr r3, [r8, #MACHINFO_PGOFFIO]
add r0, r4, r3
rsb r3, r3, #0x4000 @ PTRS_PER_PGD*sizeof(long)
cmp r3, #0x0800 @ limit to 512MB
movhi r3, #0x0800
add r6, r0, r3
ldr r3, [r8, #MACHINFO_PHYSIO]
orr r3, r3, r7
1: str r3, [r0], #4 //这个循环把 phys_io 填充到 io_pg_offst 对应的 MMU 表项中
add r3, r3, #1 << 20
teq r0, r6
bne 1b
#if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)
/*
* If we're using the NetWinder or CATS, we also need to map
* in the 16550-type serial port for the debug messages
*/
add r0, r4, #0xff000000 >> 18
orr r3, r7, #0x7c000000
str r3, [r0]
#endif
#ifdef CONFIG_ARCH_RPC
/*
* Map in screen at 0x02000000 & SCREEN2_BASE
* Similar reasons here - for debug. This is
* only for Acorn RiscPC architectures.
*/
add r0, r4, #0x02000000 >> 18
orr r3, r7, #0x02000000
str r3, [r0]
add r0, r4, #0xd8000000 >> 18
str r3, [r0]
#endif
#endif
上面蓝色加粗部分的代码是在哪里定义的呢?它是在arch\arm\kernel\asm-offsets.c定义的,请看下面加粗的代码:
int main(void)
{
DEFINE(TSK_ACTIVE_MM, offsetof(struct task_struct, active_mm));
BLANK();
DEFINE(TI_FLAGS, offsetof(struct thread_info, flags));
DEFINE(TI_PREEMPT, offsetof(struct thread_info, preempt_count));
........
........
DEFINE(SYS_ERROR0, 0x9f0000);
BLANK();
DEFINE(SIZEOF_MACHINE_DESC, sizeof(struct machine_desc));
DEFINE(MACHINFO_TYPE, offsetof(struct machine_desc, nr));
DEFINE(MACHINFO_NAME, offsetof(struct machine_desc, name));
DEFINE(MACHINFO_PHYSIO, offsetof(struct machine_desc, phys_io));
DEFINE(MACHINFO_PGOFFIO, offsetof(struct machine_desc, io_pg_offst));
BLANK();
........
.........
return 0;
}
通过以上的DEFINE宏定义取出phys_io与io_pg_offst分别赋给了MACHINE_PHYSIO和MACHINE_PGOFFIO,这样, phys_io 和 io_pg_offst 就建立了映射关系。
3. printascii 与 uart
printascii 函数调用了一个 汇编宏 addruart。 这个宏在 arch/arm/mach-XXX/include/mach/debug-macro.S 中定义。它的代码一般是这种形式:
.macro addruart,rx
@ see if the MMU is enabled and select appropriate base address
mrc p15, 0, \rx, c1, c0
tst \rx, #1
ldreq \rx, =SUART_BASE_PA
ldrne \rx, =SUART_BASE_UA
.endm
显然,这里用到了在 head.S 中建立的映射关系。这个函数有些芯片并没有去实现。这个函数只用于low level 的调试函数。
(责任编辑:IT) |