• Uncategorized

About linux : How-to-understand-Systemmap-output-from-linux-kernel-build-how-I-calculate-physical-address

Question Detail

I have built a linux kernel image (arm64) and I can do disassembly using this command (goes out to stdout).

aarch64-none-elf-objdump -b binary -D -m aarch64 Image

The output looks like this.

arch/arm64/boot/Image:     file format binary

Disassembly of section .data:

0000000000000000 <.data>:
       0:   140fc000    b   0x3f0000                          <=== see this branch to 3f0000
       4:   00000000    udf #0
       8:   00080000    .inst   0x00080000 ; undefined
       c:   00000000    udf #0
      10:   004bb000    .inst   0x004bb000 ; undefined
      14:   00000000    udf #0

  3dbe48:   756e694c    .inst   0x756e694c ; undefined
  3dbe4c:   00000078    udf #120
  3f0000:   d280067b    mov x27, #0x3333                    // #51  \
  3f0004:   5800157c    ldr x28, 0x3f02b0                            |
  3f0008:   9100239c    add x28, x28, #0x8                           | added for debug
  3f000c:   f800879b    str x27, [x28], #8                           |
  3f0010:   5800151a    ldr x26, 0x3f02b0                            |
  3f0014:   f900035c    str x28, [x26]                               /
  3f0018:   94000008    bl  0x3f0038
  3f001c:   97fc47fb    bl  0x302008

The FPGA board I’m working on has only 8 MB on-chip ram (0x80000000 ~ 0x80800000) in place of DDR range(0x80000000 ~ ) for now and I loaded the kernel image to 0x80080000 and jumped to 0x80080000. (I’m using u-boot-spl to make this jump). I can’t use debugger for the board yet and I wanted to check if the linux kernel code really runs so added a simple debug code which writes 0x3333 at some memory location. (The 6 lines at 0x3f0000 using x27 and x28 is the code.) Original linux code doesn’t have it and would do bl preserve_boot_args. (here bl 0x3f0038).
This is the debug code I added in arch/arm64/kernel/start.S. (6 linex using x27, x28)


    mov x27, #0x3333            \
    ldr x28, =myptr              |
    add x28, x28, #8             |
    str x27, [x28], #8           |  added for debug
    ldr x26, =myptr              |
    str x28, [x26]               /

    bl  preserve_boot_args
    bl  el2_setup           // Drop to EL1, w0=cpu_boot_mode

.section ".__mydebug", "aw"
myptr:  .double 0x807e0000

So if the next value of myptr is 0x3333, the code should have worked. I modified the linux linker script as below (added a section .mydebug) and made the value myptr be placed there.

    __pecoff_data_rawsize = ABSOLUTE(. - __initdata_begin);
    _edata = .;

    .mydebug : {                  \
        . = ALIGN(8);              |  ==> added section
        KEEP(*(.__mydebug));       |
    }                             /

    BSS_SECTION(0, 0, 0)

    init_pg_dir = .;

And the System.map file looks like this.

0000000000000000 A __rela_size
0000000000000000 A _kernel_flags_le_hi32
0000000000000000 A _kernel_offset_le_hi32
0000000000000000 A _kernel_size_le_hi32
000000000000000a A _kernel_flags_le_lo32
0000000000000200 A PECOFF_FILE_ALIGNMENT
000000000006b808 A __pecoff_data_rawsize
0000000000080000 A _kernel_offset_le_lo32
0000000000095000 A __pecoff_data_size
00000000004bb000 A _kernel_size_le_lo32
00000000004be948 A __rela_offset
ffffffc010080000 t _head
ffffffc010080000 T _text
ffffffc010080800 T __exception_text_start
ffffffc010080800 T _stext
ffffffc010080800 T do_undefinstr
ffffffc0100809d0 T do_sysinstr
ffffffc010080a40 T do_mem_abort
ffffffc010080ae0 T do_el0_irq_bp_hardening
ffffffc010080b60 T do_el0_ia_bp_hardening
ffffffc010511800 D secondary_holding_pen_release
ffffffc010511808 D __mmuoff_data_end
ffffffc010511808 D _edata
ffffffc010511808 D myptr              <==== see this
ffffffc010511810 B __bss_start
ffffffc010512000 b bm_pmd
ffffffc010513000 b bm_pte
ffffffc010514000 B empty_zero_page
ffffffc010515000 B reset_devices
ffffffc010515008 b execute_command
ffffffc010515010 b ramdisk_execute_command

I wanted to see the value of myptr and the next value.(all 64 bit). But the System.map shows all virtual addresses. How can I know the physical address of myptr? In previous baremetal programas, I could see the memory using the map file (it showed the physical address, virtual=physical), but in this case the System.map shows virtual addresses which I can’t localize.. I tried looking at 0x80080000 + 0x3f0004 + 0x3f02b0 or 0x80080000 + 0x3f02b0 but couldn’t find it. How can I find the location of myptr??

ADD (Jan 5, 2022) :
I found .mysection is followed by _bss which will be initialized by 0, so I added some space before _bss_start. And I thought the instruction 3f0004: 5800157c ldr x28, 0x3f02b0 is ldr (literal) instruction in armv8 arch ref manual C6.2.133 (by first two bits). So the value 0x3f02b0 is PC relative. The PC value at the instant is 0x3f0008 (already incremented by 4) so 0x3f0008 + 0x3f02b0 = 0x7e02b8. Since the kernel images starts at 0x80080000, this location is 0x80080000 + 0x7e02b8 = 0x808602b8 which goes beyond the 8MB range(0x80000000 ~ 0x80800000). If I placed the kernel at 0x80000000, this value would become 0x807e02b8 (in the RAM range).
But still there were strange values in the address next to the address I think is myptr location. And I found the PAGE_OFFSET is 0xffffff00_00000000 by printing it during compile in the file arch/arm64/include/asm/memory.h.(not 0xffffffc0_00000000 as shown in System.map). I tried looking at (address of myptr according to System.map) - PAGE_OFFSET + (kernel load address = 0x80000000) but couldn’t find 0x3333 written in address next to myptr. I tried assuming PAGE_OFFSET 0xffffffc010000000 (then myptr becomes 0x80511808) and 0xffffff0000000000 (then myptr becomes 0xc090511808 which is too big).

Question Answer

No answer for now.

You may also like...

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.