linux中内核中machine_desc,Linux下machine_desc结构体中的phys_io与io_pg_offst 的作用及使用方法...

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这结构体:

[cpp]

structmachine_desc {

/*

* Note! The first four elements are used

* by assembler code in head.S, head-common.S

*/

unsignedintnr;/* architecture number */

unsignedintphys_io;/* start of physical io */

unsignedintio_pg_offst;/* byte offset for io

* page tabe entry */

constchar*name;/* architecture name */

unsignedlongboot_params;/* tagged list  */

unsignedintvideo_start;/* start of video RAM */

unsignedintvideo_end;/* end of video RAM */

unsignedintreserve_lp0 :1;/* never has lp0 */

unsignedintreserve_lp1 :1;/* never has lp1 */

unsignedintreserve_lp2 :1;/* never has lp2 */

unsignedintsoft_reboot :1;/* soft reboot  */

void(*fixup)(structmachine_desc *,

structtag *,char**,

structmeminfo *);

void(*map_io)(void);/* IO mapping function */

void(*init_irq)(void);

structsys_timer *timer;/* system tick 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中分析这两个变量的具体调用情况:

[cpp]

/*

*  linux/arch/arm/kernel/head.S

*

*  Copyright (C) 1994-2002 Russell King

*  Copyright (c) 2003 ARM Limited

*  All Rights Reserved

*

* This program is free software; you can redistribute it and/or modify

* it under the terms of the GNU General Public License version 2 as

* published by the Free Software Foundation.

*

*  Kernel startup code for all 32-bit CPUs

*/

............

............

............

/*

* Kernel startup entry point.

* ---------------------------

*

* This is normally called from the decompressor code.  The requirements

* are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,

* r1 = machine nr, r2 = atags pointer.

*

* This code is mostly position independent, so if you link the kernel at

* 0xc0008000, you call this at __pa(0xc0008000).

*

* See linux/arch/arm/tools/mach-types for the complete list of machine

* numbers for r1.

*

* We're trying to keep crap to a minimum; DO NOT add any machine specific

* crap here - that's what the boot loader (or in extreme, well justified

* circumstances, zImage) is for.

*/

__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

/*

* The following calls CPU specific code in a position independent

* manner.  See arch/arm/mm/proc-*.S for details.  r10 = base of

* xxx_proc_info structure selected by __lookup_machine_type

* above.  On return, the CPU will be ready for the MMU to be

* turned on, and r0 will hold the CPU control register value.

*/

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)

.....

.....

.....

/*

* Setup the initial page tables.  We only setup the barest

* amount which are required to get the kernel running, which

* generally means mapping in the kernel code.

*

* r8  = machinfo

* r9  = cpuid

* r10 = procinfo

*

* Returns:

*  r0, r3, r6, r7 corrupted

*  r4 = physical page table address

*/

__create_page_tables:

pgtbl   r4              @ page table address

/*

* Clear the 16K level 1 swapper page table

*/

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

/*

* Create identity mapping for first MB of kernel to

* cater for the MMU enable.  This identity mapping

* will be removed by paging_init().  We use our current program

* counter to determine corresponding section base address.

*/

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

/*

* Now setup the pagetables for our kernel direct

* mapped region.

*/

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 <

strls   r3, [r0], #4

bls 1b

#ifdef CONFIG_XIP_KERNEL

/*

* Map some ram to cover our .data and .bss areas.

*/

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 <

strls   r3, [r0], #4

bls 1b

#endif

/*

* Then map first 1MB of ram in case it contains our boot params.

*/

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

/*

* 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

add r3, r3, #1 <

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

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 的调试函数。0b1331709591d260c1c78e86d0c51c18.png

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值