歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
您现在的位置: Linux教程網 >> UnixLinux >  >> Linux編程 >> Linux編程

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]
  1. struct machine_desc {  
  2.  /* 
  3.   * Note! The first four elements are used 
  4.   * by assembler code in head.S, head-common.S 
  5.   */  
  6.  unsigned int  nr;  /* architecture number */  
  7.  unsigned int  phys_io; /* start of physical io */  
  8.  unsigned int  io_pg_offst; /* byte offset for io  
  9.        * page tabe entry */  
  10.   
  11.  const char  *name;  /* architecture name */  
  12.  unsigned long  boot_params; /* tagged list  */  
  13.   
  14.  unsigned int  video_start; /* start of video RAM */  
  15.  unsigned int  video_end; /* end of video RAM */  
  16.   
  17.  unsigned int  reserve_lp0 :1; /* never has lp0 */  
  18.  unsigned int  reserve_lp1 :1; /* never has lp1 */  
  19.  unsigned int  reserve_lp2 :1; /* never has lp2 */  
  20.  unsigned int  soft_reboot :1; /* soft reboot  */  
  21.  void   (*fixup)(struct machine_desc *,  
  22.       struct tag *, char **,  
  23.       struct meminfo *);  
  24.  void   (*map_io)(void);/* IO mapping function */  
  25.  void   (*init_irq)(void);  
  26.  struct sys_timer *timer;  /* system tick timer */  
  27.  void   (*init_machine)(void);  
  28. };  

行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]
  1. /* 
  2.  *  linux/arch/arm/kernel/head.S 
  3.  * 
  4.  *  Copyright (C) 1994-2002 Russell King 
  5.  *  Copyright (c) 2003 ARM Limited 
  6.  *  All Rights Reserved 
  7.  * 
  8.  * This program is free software; you can redistribute it and/or modify 
  9.  * it under the terms of the GNU General Public License version 2 as 
  10.  * published by the Free Software Foundation. 
  11.  * 
  12.  *  Kernel startup code for all 32-bit CPUs 
  13.  */  
  14. ............  
  15. ............  
  16. ............  
  17. /* 
  18.  * Kernel startup entry point. 
  19.  * --------------------------- 
  20.  * 
  21.  * This is normally called from the decompressor code.  The requirements 
  22.  * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0, 
  23.  * r1 = machine nr, r2 = atags pointer. 
  24.  * 
  25.  * This code is mostly position independent, so if you link the kernel at 
  26.  * 0xc0008000, you call this at __pa(0xc0008000). 
  27.  * 
  28.  * See linux/arch/arm/tools/mach-types for the complete list of machine 
  29.  * numbers for r1. 
  30.  * 
  31.  * We're trying to keep crap to a minimum; DO NOT add any machine specific 
  32.  * crap here - that's what the boot loader (or in extreme, well justified 
  33.  * circumstances, zImage) is for. 
  34.  */  
  35.     __HEAD  
  36. ENTRY(stext)  
  37.     setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode  
  38.                         @ and irqs disabled  
  39.     mrc p15, 0, r9, c0, c0      @ get processor id  
  40.     bl  __lookup_processor_type     @ r5=procinfo r9=cpuid  
  41.     movs    r10, r5             @ invalid processor (r5=0)?  
  42.     beq __error_p           @ yes, error 'p'  
  43.     bl  __lookup_machine_type       @ r5=machinfo  
  44.     movs    r8, r5              @ invalid machine (r5=0)?  
  45.     beq __error_a           @ yes, error 'a'  
  46.     bl  __vet_atags  
  47.     bl  __create_page_tables  
  48.   
  49.     /* 
  50.      * The following calls CPU specific code in a position independent 
  51.      * manner.  See arch/arm/mm/proc-*.S for details.  r10 = base of 
  52.      * xxx_proc_info structure selected by __lookup_machine_type 
  53.      * above.  On return, the CPU will be ready for the MMU to be 
  54.      * turned on, and r0 will hold the CPU control register value. 
  55.      */  
  56.     ldr r13, __switch_data      @ address to jump to after  
  57.                         @ mmu has been enabled  
  58.     adr lr, BSYM(__enable_mmu)      @ return (PIC) address  
  59.  ARM(   add pc, r10, #PROCINFO_INITFUNC )  
  60.  THUMB( add r12, r10, #PROCINFO_INITFUNC    )  
  61.  THUMB( mov pc, r12             )  
  62. ENDPROC(stext)  
  63. .....  
  64. .....  
  65. .....  
  66. /* 
  67.  * Setup the initial page tables.  We only setup the barest 
  68.  * amount which are required to get the kernel running, which 
  69.  * generally means mapping in the kernel code. 
  70.  * 
  71.  * r8  = machinfo 
  72.  * r9  = cpuid 
  73.  * r10 = procinfo 
  74.  * 
  75.  * Returns: 
  76.  *  r0, r3, r6, r7 corrupted 
  77.  *  r4 = physical page table address 
  78.  */  
  79. __create_page_tables:  
  80.     pgtbl   r4              @ page table address  
  81.   
  82.     /* 
  83.      * Clear the 16K level 1 swapper page table 
  84.      */  
  85.     mov r0, r4  
  86.     mov r3, #0  
  87.     add r6, r0, #0x4000  
  88. 1:  str r3, [r0], #4  
  89.     str r3, [r0], #4  
  90.     str r3, [r0], #4  
  91.     str r3, [r0], #4  
  92.     teq r0, r6  
  93.     bne 1b  
  94.   
  95.     ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags  
  96.   
  97.     /* 
  98.      * Create identity mapping for first MB of kernel to 
  99.      * cater for the MMU enable.  This identity mapping 
  100.      * will be removed by paging_init().  We use our current program 
  101.      * counter to determine corresponding section base address. 
  102.      */  
  103.     mov r6, pc  
  104.     mov r6, r6, lsr #20         @ start of kernel section  
  105.     orr r3, r7, r6, lsl #20     @ flags + kernel base  
  106.     str r3, [r4, r6, lsl #2]        @ identity mapping  
  107.   
  108.     /* 
  109.      * Now setup the pagetables for our kernel direct 
  110.      * mapped region. 
  111.      */  
  112.     add r0, r4,  #(KERNEL_START & 0xff000000) >> 18  
  113.     str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!  
  114.     ldr r6, =(KERNEL_END - 1)  
  115.     add r0, r0, #4  
  116.     add r6, r4, r6, lsr #18  
  117. 1:  cmp r0, r6  
  118.     add r3, r3, #1 << 20  
  119.     strls   r3, [r0], #4  
  120.     bls 1b  
  121.   
  122. #ifdef CONFIG_XIP_KERNEL   
  123.     /* 
  124.      * Map some ram to cover our .data and .bss areas. 
  125.      */  
  126.     orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000)  
  127.     .if (KERNEL_RAM_PADDR & 0x00f00000)  
  128.     orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000)  
  129.     .endif  
  130.     add r0, r4,  #(KERNEL_RAM_VADDR & 0xff000000) >> 18  
  131.     str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!  
  132.     ldr r6, =(_end - 1)  
  133.     add r0, r0, #4  
  134.     add r6, r4, r6, lsr #18  
  135. 1:  cmp r0, r6  
  136.     add r3, r3, #1 << 20  
  137.     strls   r3, [r0], #4  
  138.     bls 1b  
  139. #endif   
  140.   
  141.     /* 
  142.      * Then map first 1MB of ram in case it contains our boot params. 
  143.      */  
  144.     add r0, r4, #PAGE_OFFSET >> 18  
  145.     orr r6, r7, #(PHYS_OFFSET & 0xff000000)  
  146.     .if (PHYS_OFFSET & 0x00f00000)  
  147.     orr r6, r6, #(PHYS_OFFSET & 0x00f00000)  
  148.     .endif  
  149.     str r6, [r0]  
  150.   
  151. #ifdef CONFIG_DEBUG_LL   
  152.     ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags  
  153.     /* 
  154.      * Map in IO space for serial debugging. 
  155.      * This allows debug messages to be output 
  156.      * via a serial console before paging_init. 
  157.      */  
  158.     ldr r3, [r8, #MACHINFO_PGOFFIO]  
  159.     add r0, r4, r3  
  160.     rsb r3, r3, #0x4000         @ PTRS_PER_PGD*sizeof(long)  
  161.     cmp r3, #0x0800         @ limit to 512MB  
  162.     movhi   r3, #0x0800  
  163.     add r6, r0, r3  
  164.     ldr r3, [r8, #MACHINFO_PHYSIO]  
  165.     orr r3, r3, r7  
  166. 1:  str r3, [r0], #4  
  167.     add r3, r3, #1 << 20  
  168.     teq r0, r6  
  169.     bne 1b  
  170. #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)   
  171.     /* 
  172.      * If we're using the NetWinder or CATS, we also need to map 
  173.      * in the 16550-type serial port for the debug messages 
  174.      */  
  175.     add r0, r4, #0xff000000 >> 18  
  176.     orr r3, r7, #0x7c000000  
  177.     str r3, [r0]  
  178. #endif   
  179. #ifdef CONFIG_ARCH_RPC   
  180.     /* 
  181.      * Map in screen at 0x02000000 & SCREEN2_BASE 
  182.      * Similar reasons here - for debug.  This is 
  183.      * only for Acorn RiscPC architectures. 
  184.      */  
  185.     add r0, r4, #0x02000000 >> 18  
  186.     orr r3, r7, #0x02000000  
  187.     str r3, [r0]  
  188.     add r0, r4, #0xd8000000 >> 18  
  189.     str r3, [r0]  
  190. #endif   
  191. #endif   
  192.     mov pc, lr  
  193. 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 的調試函數。

Copyright © Linux教程網 All Rights Reserved