/* * Physical vs virtual RAM address space conversion. These are * private definitions which should NOT be used outside memory.h * files. Use virt_to_phys/phys_to_virt/__pa/__va instead. */ #define __virt_to_phys(x) (((phys_addr_t)(x) - PAGE_OFFSET + PHYS_OFFSET)) #define __phys_to_virt(x) ((unsigned long)((x) - PHYS_OFFSET + PAGE_OFFSET))
这里就没有用__ASSEMBLY__。
看下内核文档的说明, 在Documentation/arm/Porting里:
PHYS_OFFSET Physical start address of the first bank of RAM.
PAGE_OFFSET Virtual start address of the first bank of RAM. During the kernel boot phase, virtual address PAGE_OFFSET will be mapped to physical address PHYS_OFFSET, along with any other mappings you supply. This should be the same value as TASK_SIZE.
PAGE_OFFSET代码定义:
/* * PAGE_OFFSET - the virtual address of the start of the kernel image (top * (VA_BITS - 1)) * VA_BITS - the maximum number of bits for virtual addresses. * VA_START - the first kernel virtual address. * TASK_SIZE - the maximum size of a user space task. * TASK_UNMAPPED_BASE - the lower boundary of the mmap VM area. * The module space lives between the addresses given by TASK_SIZE * and PAGE_OFFSET - it must be within 128MB of the kernel text. */ #define VA_BITS (CONFIG_ARM64_VA_BITS) #define VA_START (UL(0xffffffffffffffff) << VA_BITS) #define PAGE_OFFSET (UL(0xffffffffffffffff) << (VA_BITS - 1))
/* * The following fragment of code is executed with the MMU on in MMU mode, and * uses absolute addresses; this is not position independent. */ __mmap_switched: adr x3, __switch_data + 8
ENTRY(stext) mov x21, x0 // x21=FDT bl el2_setup // Drop to EL1, w20=cpu_boot_mode bl __calc_phys_offset // x24=PHYS_OFFSET, x28=PHYS_OFFSET-PAGE_OFFSET
/* * Calculate the start of physical memory. */ __calc_phys_offset: adr x0, 1f ldp x1, x2, [x0] sub x28, x0, x1 // x28 = PHYS_OFFSET - PAGE_OFFSET add x24, x2, x28 // x24 = PHYS_OFFSET ret ENDPROC(__calc_phys_offset)
.align 3 1: .quad . .quad PAGE_OFFSET
没有看明白上面计算方法主要是因为.quad .
先看下out下System.map, 能看出这里都是虚拟地址了。
6 ffffffc000080000 T _text 7 ffffffc000080000 t efi_head 8 ffffffc000080040 t pe_header 9 ffffffc000080044 t coff_header 10 ffffffc000080058 t optional_header 11 ffffffc000080070 t extra_header_fields 12 ffffffc0000800f8 t section_table 13 ffffffc000081000 T stext
看下BL/LK的跳转地址log:
[2180] booting linux @ 0x80080000, ramdisk @ 0x83600000 (2209319), tags/device tree @ 0x83400000
这里jump addr就是0x80080000, ddr base is 0x80000000, 偏移是0x80000从kernel/arch/arm64也能看出来:
# The byte offset of the kernel image in RAM from the start of RAM. ifeq ($(CONFIG_ARM64_RANDOMIZE_TEXT_OFFSET), y) TEXT_OFFSET := $(shell awk 'BEGIN {srand(); printf "0x%03x000\n", int(512 * rand())}') else TEXT_OFFSET := 0x00080000 endif
加了个打印看到memstart_addr是0x80000000。
arm64 code is based on arm32, 查下git log:
commit 72a20e22f49e2dad3180c23980a9df1c63faab0a Author: Russell King <rmk+kernel@arm.linux.org.uk> Date: Tue Jan 4 19:04:00 2011 +0000
ARM: P2V: eliminate head.S use of PHYS_OFFSET for !XIP_KERNEL head.S makes use of PHYS_OFFSET. When it becomes a variable, the assembler won't understand this. Compute PHYS_OFFSET by the following method. This code is linked at its virtual address, but run at before the MMU is enabled, so at his physical address.
1: .long . .long PAGE_OFFSET adr r0, 1b @ r0 = physical ',' ldmia r0, {r1, r2} @ r1 = virtual '.', r2 = PAGE_OFFSET sub r1, r0, r1 @ r1 = physical-virtual add r2, r2, r1 @ r2 = PAGE_OFFSET + physical-virtual @ := PHYS_OFFSET. Switch XIP users of PHYS_OFFSET to use PLAT_PHYS_OFFSET - we can't use this method for XIP kernels as the code doesn't execute in RAM.
Tested-by: Tony Lindgren <tony@atomide.com> Reviewed-by: Nicolas Pitre <nicolas.pitre@linaro.org> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
The special symbol . refers to the current address that as is assembling into. Thus, the expression melvin: .long . defines melvin to contain its own address. Assigning a value to . is treated the same as a .org directive. Thus, the expression .=.+4 is the same as saying .space 4.
这里提到就是链接地址也就是虚拟地址,而adr x0, 1b, 此时的环境没有打开mmu所以此时是物理地址。回过头就能理解git的注释 - This code is linked at its virtual address, but run at before the MMU is enabled, so at his physical address