unbutun 发表于 2013-08-18 07:26

arm上这个pv_stub有什么用?

arm上这个pv_stub有什么用?

看着咋定义CONFIG_ARM_PATCH_PHYS_VIRT之后virt_to_phys偏移就加错了,算错了呢,有了解这个的大侠不?

-------------------------------------------------------------------------------------------------------------------------------------------------------
include/asm/memory.h
-------------------------------------------------------------------------------------------------------------------------------------------------------
146/*
147 * Physical vs virtual RAM address space conversion.These are
148 * private definitions which should NOT be used outside memory.h
149 * files.Use virt_to_phys/phys_to_virt/__pa/__va instead.
150 */
151#ifndef __virt_to_phys
152#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
153
154/*
155 * Constants used to force the right instruction encodings and shifts
156 * so that all we need to do is modify the 8-bit constant field.
157 */
158#define __PV_BITS_31_24 0x81000000
159
160extern unsigned long __pv_phys_offset;
161#define PHYS_OFFSET __pv_phys_offset
162
163#define __pv_stub(from,to,instr,type)                   \
164      __asm__("@ __pv_stub\n"                         \
165      "1:   " instr "       %0, %1, %2\n"         \
166      "       .pushsection .pv_table,\"a\"\n"         \
167      "       .long   1b\n"                           \
168      "       .popsection\n"                        \
169      : "=r" (to)                                     \
170      : "r" (from), "I" (type))
171
172static inline unsigned long __virt_to_phys(unsigned long x)
173{
174      unsigned long t;
175      __pv_stub(x, t, "add", __PV_BITS_31_24);
176      return t;
177}
178
179static inline unsigned long __phys_to_virt(unsigned long x)
180{
181      unsigned long t;
182      __pv_stub(x, t, "sub", __PV_BITS_31_24);
183      return t;
184}
185#else
186#define __virt_to_phys(x)       ((x) - PAGE_OFFSET + PHYS_OFFSET)
187#define __phys_to_virt(x)       ((x) - PHYS_OFFSET + PAGE_OFFSET)
188#endif
189#endif
190#endif /* __ASSEMBLY__ */
191
192#ifndef PHYS_OFFSET
193#ifdef PLAT_PHYS_OFFSET
194#define PHYS_OFFSET   PLAT_PHYS_OFFSET
195#else
196#define PHYS_OFFSET   UL(CONFIG_PHYS_OFFSET)
197#endif
198#endif

------------------------------------------------------------------------------------------------------------------------------------------------------
arch/arm/kernel/vmlinux.lds.S
------------------------------------------------------------------------------------------------------------------------------------------------------
197      .init.pv_table : {
198                __pv_table_begin = .;
199                *(.pv_table)
200                __pv_table_end = .;
201      }
------------------------------------------------------------------------------------------------------------------------------------------------------
arch/arm/kernel/module.c
------------------------------------------------------------------------------------------------------------------------------------------------------
319#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
320      s = find_mod_section(hdr, sechdrs, ".pv_table");
321      if (s)
322                fixup_pv_table((void *)s->sh_addr, s->sh_size);
323#endif
------------------------------------------------------------------------------------------------------------------------------------------------------
arch/arm/kernel/head.S
------------------------------------------------------------------------------------------------------------------------------------------------------
541#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
542
543/* __fixup_pv_table - patch the stub instructions with the delta between
544 * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and
545 * can be expressed by an immediate shifter operand. The stub instruction
546 * has a form of '(add|sub) rd, rn, #imm'.
547 */
548      __HEAD
549__fixup_pv_table:
550      adr   r0, 1f
551      ldmia   r0, {r3-r5, r7}
552      sub   r3, r0, r3      @ PHYS_OFFSET - PAGE_OFFSET
553      add   r4, r4, r3      @ adjust table start address
554      add   r5, r5, r3      @ adjust table end address
555      add   r7, r7, r3      @ adjust __pv_phys_offset address
556      str   r8,       @ save computed PHYS_OFFSET to __pv_phys_offset
557      mov   r6, r3, lsr #24 @ constant for add/sub instructions
558      teq   r3, r6, lsl #24 @ must be 16MiB aligned
559THUMB(it      ne            @ cross section branch )
560      bne   __error
561      str   r6,     @ save to __pv_offset
562      b       __fixup_a_pv_table
563ENDPROC(__fixup_pv_table)
564
565      .align
5661:      .long   .
567      .long   __pv_table_begin
568      .long   __pv_table_end
5692:      .long   __pv_phys_offset
570
571      .text
572__fixup_a_pv_table:
573#ifdef CONFIG_THUMB2_KERNEL
574      lsls    r6, #24
575      beq   2f
576      clz   r7, r6
577      lsr   r6, #24
578      lsl   r6, r7
579      bic   r6, #0x0080
580      lsrs    r7, #1
581      orrcs   r6, #0x0080
582      orr   r6, r6, r7, lsl #12
583      orr   r6, #0x4000
584      b       2f
5851:      add   r7, r3
586      ldrh    ip,
587      and   ip, 0x8f00
588      orr   ip, r6@ mask in offset bits 31-24
589      strh    ip,
5902:      cmp   r4, r5
591      ldrcc   r7, , #4    @ use branch for delay slot
592      bcc   1b
593      bx      lr
594#else
595      b       2f
5961:      ldr   ip,
597      bic   ip, ip, #0x000000ff
598      orr   ip, ip, r6      @ mask in offset bits 31-24
599      str   ip,
6002:      cmp   r4, r5
601      ldrcc   r7, , #4    @ use branch for delay slot
602      bcc   1b
603      mov   pc, lr
604#endif
605ENDPROC(__fixup_a_pv_table)
606
607ENTRY(fixup_pv_table)
608      stmfd   sp!, {r4 - r7, lr}
609      ldr   r2, 2f                  @ get address of __pv_phys_offset
610      mov   r3, #0                  @ no offset
611      mov   r4, r0                  @ r0 = table start
612      add   r5, r0, r1            @ r1 = table size
613      ldr   r6,             @ get __pv_offset
614      bl      __fixup_a_pv_table
615      ldmfd   sp!, {r4 - r7, pc}
616ENDPROC(fixup_pv_table)
617
618      .align
6192:      .long   __pv_phys_offset
620
621      .data
622      .globl__pv_phys_offset
623      .type   __pv_phys_offset, %object
624__pv_phys_offset:
625      .long   0
626      .size   __pv_phys_offset, . - __pv_phys_offset
627__pv_offset:
628      .long   0
629#endif

unbutun 发表于 2013-08-23 19:10

知道答案了,用来支持动态重定位的

wth0722 发表于 2014-12-17 14:15

回复 2# unbutun


有那為高手可以解釋一下嗎?

為什麼可以做到動態轉換?


我目前卡在#define __pv_stub(from,to,instr,type)         \
    __asm__("@ __pv_stub\n"             \
    "1: " instr "   %0, %1, %2\n"       \
    "   .pushsection .pv_table,\"a\"\n"   \
    "   .long   1b\n"               \
    "   .popsection\n"            \
    : "=r" (to)               \
    : "r" (from), "I" (type))粗體字那幾行看不太懂為何這樣做

   

arm-linux-gcc 发表于 2014-12-17 16:36

本帖最后由 arm-linux-gcc 于 2014-12-26 20:27 编辑

回复 3# wth0722


    内核启动过程中会去根据实际物理地址修改这个段中的指令,所以代码中看到的是写成的一个固定的数字,但是实际运行时会去修改指令中的参数域,

由于这个参数域size有特殊的限制,所以内核放置的物理地址必须按照16M对齐


wth0722 发表于 2014-12-19 13:42

回复 4# arm-linux-gcc


首先先感謝你的回復

我想要問的是下面那三行是代表什麼意思

"   .pushsection .pv_table,\"a\"\n"   \
"   .long   1b\n"               \
"   .popsection\n"

   

wth0722 发表于 2014-12-19 13:45

我從readelf是有看到pv_table那section,但那是代表什麼意思?

.init.pv_table    PROGBITS      c047b5ac 4835ac 000624 00   A0   01

   

arm-linux-gcc 发表于 2014-12-20 17:20

本帖最后由 arm-linux-gcc 于 2014-12-20 17:22 编辑

wth0722 发表于 2014-12-19 13:42 static/image/common/back.gif
回复 4# arm-linux-gcc





在这个.o文件中插入一个段,段名为.pv_table
段的内容是个long型的,其值是个地址,即前面标号为1处的地址



163#define __pv_stub(from,to,instr,type)                   \
164      __asm__("@ __pv_stub\n"                         \
165      "1:   " instr "       %0, %1, %2\n"         \    插入一条指令到当前文件中,由于__pv_stub这个宏是在代码中被调用的,所以这一条插入的指令是在当前.o文件的text段,这里还定义了标号1
166      "       .pushsection .pv_table,\"a\"\n"         \   在当前.o文件的.text里插入一个名为.pv_table的段
167      "       .long   1b\n"                           \            这个段的内容是个地址,这个地址指向的前面的标号1(1b表示backword 1,1f表示forword 1,1b就表示在本句之前找到标号1,假如这里的1b改成1f,那么就会在本句后面去找标号1)
168      "       .popsection\n"                        \          .pv_table结束,之后的仍然归于.text段
169      : "=r" (to)                                     \
170      : "r" (from), "I" (type))





197      .init.pv_table : {
198                __pv_table_begin = .;
199                *(.pv_table)
200                __pv_table_end = .;
201      }
会将所有.o文件中的.pv_table段抓出来放在vmlinux的.init.pv_table段中,这个段中每一个long型都是指向一个地址,位于这些地址处的内容就是各个标号1处的指令
于是在内核启动时就能够通过__pv_table_begin找到所有的这些标号1处的指令,然后就可以修改这些指令的操作数了


wth0722 发表于 2014-12-22 14:24

你的意思是不是在編譯時, 把 "1:   " instr "       %0, %1, %2\n"所在的位址儲存到.init.pv_table section裡面 ?

如果是的話,請問一下儲存他有何意義?

wth0722 发表于 2014-12-22 14:33

還有Run time時,當呼叫了y=virt_to_phys(x)之後,那個y跟所儲存的那資訊有什麼關係

感謝你的回答

arm-linux-gcc 发表于 2014-12-22 17:43

回复 8# wth0722


    是为了能够找到这些指令,内核启动时会修改这个指令的参数域,如果不记录地址,那么如何找到这些指令?
页: [1] 2
查看完整版本: arm上这个pv_stub有什么用?