歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> Linux下machine_desc結構體中的phys_io與io_pg_offst 的作用及使用方法

Linux下machine_desc結構體中的phys_io與io_pg_offst 的作用及使用方法

日期:2017/3/1 10:32:16   编辑: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這結構體:

[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. const char *name; /* architecture name */
  11. unsigned long boot_params; /* tagged list */
  12. unsigned int video_start; /* start of video RAM */
  13. unsigned int video_end; /* end of video RAM */
  14. unsigned int reserve_lp0 :1; /* never has lp0 */
  15. unsigned int reserve_lp1 :1; /* never has lp1 */
  16. unsigned int reserve_lp2 :1; /* never has lp2 */
  17. unsigned int soft_reboot :1; /* soft reboot */
  18. void (*fixup)(struct machine_desc *,
  19. struct tag *, char **,
  20. struct meminfo *);
  21. void (*map_io)(void);/* IO mapping function */
  22. void (*init_irq)(void);
  23. struct sys_timer *timer; /* system tick timer */
  24. void (*init_machine)(void);
  25. };

行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. * The following calls CPU specific code in a position independent
  50. * manner. See arch/arm/mm/proc-*.S for details. r10 = base of
  51. * xxx_proc_info structure selected by __lookup_machine_type
  52. * above. On return, the CPU will be ready for the MMU to be
  53. * turned on, and r0 will hold the CPU control register value.
  54. */
  55. ldr r13, __switch_data @ address to jump to after
  56. @ mmu has been enabled
  57. adr lr, BSYM(__enable_mmu) @ return (PIC) address
  58. ARM( add pc, r10, #PROCINFO_INITFUNC )
  59. THUMB( add r12, r10, #PROCINFO_INITFUNC )
  60. THUMB( mov pc, r12 )
  61. ENDPROC(stext)
  62. .....
  63. .....
  64. .....
  65. /*
  66. * Setup the initial page tables. We only setup the barest
  67. * amount which are required to get the kernel running, which
  68. * generally means mapping in the kernel code.
  69. *
  70. * r8 = machinfo
  71. * r9 = cpuid
  72. * r10 = procinfo
  73. *
  74. * Returns:
  75. * r0, r3, r6, r7 corrupted
  76. * r4 = physical page table address
  77. */
  78. __create_page_tables:
  79. pgtbl r4 @ page table address
  80. /*
  81. * Clear the 16K level 1 swapper page table
  82. */
  83. mov r0, r4
  84. mov r3, #0
  85. add r6, r0, #0x4000
  86. 1: str r3, [r0], #4
  87. str r3, [r0], #4
  88. str r3, [r0], #4
  89. str r3, [r0], #4
  90. teq r0, r6
  91. bne 1b
  92. ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags
  93. /*
  94. * Create identity mapping for first MB of kernel to
  95. * cater for the MMU enable. This identity mapping
  96. * will be removed by paging_init(). We use our current program
  97. * counter to determine corresponding section base address.
  98. */
  99. mov r6, pc
  100. mov r6, r6, lsr #20 @ start of kernel section
  101. orr r3, r7, r6, lsl #20 @ flags + kernel base
  102. str r3, [r4, r6, lsl #2] @ identity mapping
  103. /*
  104. * Now setup the pagetables for our kernel direct
  105. * mapped region.
  106. */
  107. add r0, r4, #(KERNEL_START & 0xff000000) >> 18
  108. str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!
  109. ldr r6, =(KERNEL_END - 1)
  110. add r0, r0, #4
  111. add r6, r4, r6, lsr #18
  112. 1: cmp r0, r6
  113. add r3, r3, #1 << 20
  114. strls r3, [r0], #4
  115. bls 1b
  116. #ifdef CONFIG_XIP_KERNEL
  117. /*
  118. * Map some ram to cover our .data and .bss areas.
  119. */
  120. orr r3, r7, #(KERNEL_RAM_PADDR & 0xff000000)
  121. .if (KERNEL_RAM_PADDR & 0x00f00000)
  122. orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00000)
  123. .endif
  124. add r0, r4, #(KERNEL_RAM_VADDR & 0xff000000) >> 18
  125. str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00000) >> 18]!
  126. ldr r6, =(_end - 1)
  127. add r0, r0, #4
  128. add r6, r4, r6, lsr #18
  129. 1: cmp r0, r6
  130. add r3, r3, #1 << 20
  131. strls r3, [r0], #4
  132. bls 1b
  133. #endif
  134. /*
  135. * Then map first 1MB of ram in case it contains our boot params.
  136. */
  137. add r0, r4, #PAGE_OFFSET >> 18
  138. orr r6, r7, #(PHYS_OFFSET & 0xff000000)
  139. .if (PHYS_OFFSET & 0x00f00000)
  140. orr r6, r6, #(PHYS_OFFSET & 0x00f00000)
  141. .endif
  142. str r6, [r0]
  143. #ifdef CONFIG_DEBUG_LL
  144. ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags
  145. /*
  146. * Map in IO space for serial debugging.
  147. * This allows debug messages to be output
  148. * via a serial console before paging_init.
  149. */
  150. ldr r3, [r8, #MACHINFO_PGOFFIO]
  151. add r0, r4, r3
  152. rsb r3, r3, #0x4000 @ PTRS_PER_PGD*sizeof(long)
  153. cmp r3, #0x0800 @ limit to 512MB
  154. movhi r3, #0x0800
  155. add r6, r0, r3
  156. ldr r3, [r8, #MACHINFO_PHYSIO]
  157. orr r3, r3, r7
  158. 1: str r3, [r0], #4
  159. add r3, r3, #1 << 20
  160. teq r0, r6
  161. bne 1b
  162. #if defined(CONFIG_ARCH_NETWINDER) || defined(CONFIG_ARCH_CATS)
  163. /*
  164. * If we're using the NetWinder or CATS, we also need to map
  165. * in the 16550-type serial port for the debug messages
  166. */
  167. add r0, r4, #0xff000000 >> 18
  168. orr r3, r7, #0x7c000000
  169. str r3, [r0]
  170. #endif
  171. #ifdef CONFIG_ARCH_RPC
  172. /*
  173. * Map in screen at 0x02000000 & SCREEN2_BASE
  174. * Similar reasons here - for debug. This is
  175. * only for Acorn RiscPC architectures.
  176. */
  177. add r0, r4, #0x02000000 >> 18
  178. orr r3, r7, #0x02000000
  179. str r3, [r0]
  180. add r0, r4, #0xd8000000 >> 18
  181. str r3, [r0]
  182. #endif
  183. #endif
  184. mov pc, lr
  185. 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