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 知道答案了,用来支持动态重定位的 回复 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-26 20:27 编辑
回复 3# wth0722
内核启动过程中会去根据实际物理地址修改这个段中的指令,所以代码中看到的是写成的一个固定的数字,但是实际运行时会去修改指令中的参数域,
由于这个参数域size有特殊的限制,所以内核放置的物理地址必须按照16M对齐
回复 4# arm-linux-gcc
首先先感謝你的回復
我想要問的是下面那三行是代表什麼意思
" .pushsection .pv_table,\"a\"\n" \
" .long 1b\n" \
" .popsection\n"
我從readelf是有看到pv_table那section,但那是代表什麼意思?
.init.pv_table PROGBITS c047b5ac 4835ac 000624 00 A0 01
本帖最后由 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处的指令,然后就可以修改这些指令的操作数了
你的意思是不是在編譯時, 把 "1: " instr " %0, %1, %2\n"所在的位址儲存到.init.pv_table section裡面 ?
如果是的話,請問一下儲存他有何意義? 還有Run time時,當呼叫了y=virt_to_phys(x)之後,那個y跟所儲存的那資訊有什麼關係
感謝你的回答
回复 8# wth0722
是为了能够找到这些指令,内核启动时会修改这个指令的参数域,如果不记录地址,那么如何找到这些指令?
页:
[1]
2