免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
12下一页
最近访问板块 发新帖
查看: 7771 | 回复: 13
打印 上一主题 下一主题

[CPU及多核] arm上这个pv_stub有什么用? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-08-18 07:26 |只看该作者 |倒序浏览
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, [r7]        @ 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, [r7, #4]    @ 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, [r7, #2]
587        and     ip, 0x8f00
588        orr     ip, r6  @ mask in offset bits 31-24
589        strh    ip, [r7, #2]
5902:      cmp     r4, r5
591        ldrcc   r7, [r4], #4    @ use branch for delay slot
592        bcc     1b
593        bx      lr
594#else
595        b       2f
5961:      ldr     ip, [r7, r3]
597        bic     ip, ip, #0x000000ff
598        orr     ip, ip, r6      @ mask in offset bits 31-24
599        str     ip, [r7, r3]
6002:      cmp     r4, r5
601        ldrcc   r7, [r4], #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, [r2, #4]            @ 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

论坛徽章:
0
2 [报告]
发表于 2013-08-23 19:10 |只看该作者
知道答案了,用来支持动态重定位的

论坛徽章:
0
3 [报告]
发表于 2014-12-17 14:15 |只看该作者
回复 2# unbutun


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

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


我目前卡在
  1. #define __pv_stub(from,to,instr,type)           \
  2.     __asm__("@ __pv_stub\n"             \
  3.     "1: " instr "   %0, %1, %2\n"       \
  4. [b]    "   .pushsection .pv_table,\"a\"\n"     \
  5.     "   .long   1b\n"               \
  6.     "   .popsection\n"              \[/b]
  7.     : "=r" (to)                 \
  8.     : "r" (from), "I" (type))
复制代码
粗體字那幾行看不太懂為何這樣做

   

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
4 [报告]
发表于 2014-12-17 16:36 |只看该作者
本帖最后由 arm-linux-gcc 于 2014-12-26 20:27 编辑

回复 3# wth0722


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

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


论坛徽章:
0
5 [报告]
发表于 2014-12-19 13:42 |只看该作者
回复 4# arm-linux-gcc


首先先感謝你的回復

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

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

   

论坛徽章:
0
6 [报告]
发表于 2014-12-19 13:45 |只看该作者
我從readelf是有看到pv_table那section,但那是代表什麼意思?

[21] .init.pv_table    PROGBITS        c047b5ac 4835ac 000624 00   A  0   0  1

   

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
7 [报告]
发表于 2014-12-20 17:20 |只看该作者
本帖最后由 arm-linux-gcc 于 2014-12-20 17:22 编辑
wth0722 发表于 2014-12-19 13:42
回复 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处的指令,然后就可以修改这些指令的操作数了


论坛徽章:
0
8 [报告]
发表于 2014-12-22 14:24 |只看该作者
你的意思是不是在編譯時, 把 "1:     " instr "       %0, %1, %2\n"  所在的位址儲存到.init.pv_table section裡面 ?

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

论坛徽章:
0
9 [报告]
发表于 2014-12-22 14:33 |只看该作者
還有Run time時,當呼叫了y=virt_to_phys(x)之後,那個y跟所儲存的那資訊有什麼關係

感謝你的回答

论坛徽章:
1
2015年迎新春徽章
日期:2015-03-04 09:58:11
10 [报告]
发表于 2014-12-22 17:43 |只看该作者
回复 8# wth0722


    是为了能够找到这些指令,内核启动时会修改这个指令的参数域,如果不记录地址,那么如何找到这些指令?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP