Skip to content

vmlinux

Steve edited this page Jul 13, 2019 · 1 revision

[HOME]

커널 빌드

커널 이미지 빌드시 vmlinux.ld.S(linux-5.1.15\arch\arm64\kernel)을 이용하여 vmlinux.ld(linux-5.1.15\arch\arm64\kernel) 파일을 생성합니다.
즉, 어셈블러로 작성된 vmlinux.ld.S 파일에서 링커가 참조 할수 있는 vmlinux.ld 파일을 생성합니다.
링커는 링커스크립트(= vmlinux.ld)를 참조하여 vmlinux를 만듭니다.

vmlinux (커널이미지)

빌드된 커널 이미지는 ELF 포멧으로 구성되어 있습니다.

vmlinux.ld (linux-5.1.15\vmlinux_readelf)
vmlinux elf (linux-5.1.15\vmlinux_readelf)

분석중인 head.S에서는 3개의 section을 가지고 있습니다.

     73:    __HEAD  (#define __HEAD  .section    ".head.text","ax")
     84:        b   stext

    105:    __INIT  (#define __INIT  .section    ".init.text","ax")
    117:        ENTRY(stext)
    137:        preserve_boot_args
    287:        __create_page_tables
    423:        __primary_switched

    474:    .section ".idmap.text","awx"
    476:        ENTRY(kimage_vaddr)
    487:        ENTRY(el2_setup)
    679:        ENTRY(__boot_cpu_mode)
    686:        ENTRY(__early_cpu_boot_status)
    695:        ENTRY(secondary_holding_pen)
    713:        ENTRY(secondary_entry)
    776:        ENTRY(__enable_mmu)
    802:        ENTRY(__cpu_secondary_check52bitva)

참고로 vmlinux.ld.S의 idmap 관련 입니다.
#define IDMAP_TEXT                      \
            . = ALIGN(SZ_4K);           \
            __idmap_text_start = .;     \
            *(.idmap.text)              \
            __idmap_text_end = .;

    .text : {               /* Real text segment            */
        _stext = .;         /* Text and read-only data      */
            __exception_text_start = .;
            *(.exception.text)
            __exception_text_end = .;
            IRQENTRY_TEXT
            SOFTIRQENTRY_TEXT
            ENTRY_TEXT
            TEXT_TEXT
            SCHED_TEXT
            CPUIDLE_TEXT
            LOCK_TEXT
            KPROBES_TEXT
            HYPERVISOR_TEXT
            IDMAP_TEXT
            HIBERNATE_TEXT
            TRAMP_TEXT
            *(.fixup)
            *(.gnu.warning)
        . = ALIGN(16);
        *(.got)            /* Global offset table        */
    }
.idmap.text 는 .text section에 포함됩니다.

vmlinux elf에서 section을 확인해 보면 아래와 같습니다.

Section Headers:
  [Nr] Name              Type             Address           Offset       Flags
* [ 1] .head.text        PROGBITS         ffff000010080000  00010000      AX  
* [ 2] .text             PROGBITS         ffff000010081000  00011000      AX  
  [ 3] .rodata           PROGBITS         ffff000010ba0000  00b30000      WA  
  [ 4] .pci_fixup        PROGBITS         ffff0000110c3490  01053490       A  
  [ 5] __ksymtab         PROGBITS         ffff0000110c5670  01055670       A  
  [ 6] __ksymtab_gpl     PROGBITS         ffff0000110cf218  0105f218       A  
  [ 7] __ksymtab_strings PROGBITS         ffff0000110da740  0106a740       A  
  [ 8] __param           PROGBITS         ffff00001110ee88  0109ee88       A  
  [ 9] __modver          PROGBITS         ffff0000111125b0  010a25b0       A  
  [10] __ex_table        PROGBITS         ffff000011113000  010a3000       A  
  [11] .notes            NOTE             ffff000011115528  010a5528       A  
* [12] .init.text        PROGBITS         ffff000011120000  010b0000      AX  
  [13] .exit.text        PROGBITS         ffff000011185c8c  01115c8c      AX  
  [14] .altinstructions  PROGBITS         ffff00001118aac8  0111aac8       A  
  [15] .altinstr_replace PROGBITS         ffff0000111caf38  0115af38      AX  
  [16] .init.data        PROGBITS         ffff0000111e8000  01178000      WA  
  [17] .data..percpu     PROGBITS         ffff00001126f000  011ff000      WA  
  [18] .data             PROGBITS         ffff000011280000  01210000      WA  
  [19] __bug_table       PROGBITS         ffff000011419ca0  013a9ca0      WA  
  [20] .mmuoff.data.writ PROGBITS         ffff00001142c000  013bc000      WA  
  [21] .mmuoff.data.read PROGBITS         ffff00001142c800  013bc800      WA  
  [22] .pecoff_edata_pad PROGBITS         ffff00001142c808  013bc808      WA  
  [23] .bss              NOBITS           ffff00001142d000  013bca00      WA  

Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings), I (info),
  L (link order), O (extra OS processing required), G (group), T (TLS),
  C (compressed), x (unknown), o (OS specific), E (exclude),
  p (processor specific)


Section Heaers
  [Nr] Name             Address             Size   
* [ 1] .head.text       ffff000010080000    00001000         4KB
* [ 2] .text            ffff000010081000    00B11740    약  12MB
* [12] .init.text       ffff000011120000    00065C8C    약 197KB

부트로더

부트로더는 커널이미지를 RAM에 로딩하고 Kernel의 Entry Point(b stext)를 호출 해줍니다.

이때 부트로더는 커널이미지에서 64-byte 헤더를 읽어 정보를 취득합니다.

    The decompressed kernel image contains a 64-byte header as follows:

      u32 code0;                /* Executable code */
      u32 code1;                /* Executable code */
      u64 text_offset;          /* Image load offset, little endian */
      u64 image_size;           /* Effective Image size, little endian */
      u64 flags;                /* kernel flags, little endian */
      u64 res2  = 0;            /* reserved */
      u64 res3  = 0;            /* reserved */
      u64 res4  = 0;            /* reserved */
      u32 magic = 0x644d5241;   /* Magic number, little endian, "ARM\x64" */
      u32 res5;                 /* reserved (used for PE COFF offset) */


    Header notes:

    - As of v3.17, all fields are little endian unless stated otherwise.

    - code0/code1 are responsible for branching to stext.

    - when booting through EFI, code0/code1 are initially skipped.
      res5 is an offset to the PE header and the PE header has the EFI
      entry point (efi_stub_entry).  When the stub has done its work, it
      jumps to code0 to resume the normal boot process.

    - Prior to v3.17, the endianness of text_offset was not specified.  In
      these cases image_size is zero and text_offset is 0x80000 in the
      endianness of the kernel.  Where image_size is non-zero image_size is
      little-endian and must be respected.  Where image_size is zero,
      text_offset can be assumed to be 0x80000.

    - The flags field (introduced in v3.17) is a little-endian 64-bit field
      composed as follows:
      Bit 0:	Kernel endianness.  1 if BE, 0 if LE.
      Bit 1-2:	Kernel Page size.
                    0 - Unspecified.
                    1 - 4K
                    2 - 16K
                    3 - 64K
      Bit 3:	Kernel physical placement
                    0 - 2MB aligned base should be as close as possible
                        to the base of DRAM, since memory below it is not
                        accessible via the linear mapping
                    1 - 2MB aligned base may be anywhere in physical
                        memory
      Bits 4-63:	Reserved.

vmlinux 64Byte Header

vmlinux 64Byte Header 분석

    code0/code1     = are responsible for branching to stext.
    text_offset     = 0x00000000-00080000
    image_size      = 0x00000000-01420000
    flags           = 0x00000000-0000000A : LE, 4K, 2MB aligned base may be anywhere in physical memory
    res2            = 0x00000000-00000000
    res3            = 0x00000000-00000000
    res4            = 0x00000000-00000000
    magic           = 0x644D5241
    res5            = 0x00000040

부트로더는 커널 이미지를 RAM의 2MB 정렬된 위치에 놓고 code0/code1을 이용해서 stext로 분기합니다.

Pinciples of ARM memory maps(참고자료/arm/principles_of_arm_memory_maps.pdf) 문서에 보면 아래와 같이 Guide를 하고 있습니다.

| | Physical Address in Soc | | 2 GBytes (32-bit map) | 0x00 8000 0000 ~ 0x00 FFFF FFFF | | 30 GBytes (36-bit map) | 0x08 8000 0000 ~ 0x0F FFFF FFFF | | 32 GBytes (40-bit map) | 0x88 0000 0000 ~ 0x8F FFFF FFFF |

계산하기 쉽게 DRAM의 영역이 0x88 0000 0000 (40-bit map) 부터 시작한다고 가정합니다. 그리고 vmlinux(커널 이미지) 물리 메모리의 맨 처음에 올라간다고 가정합니다.

vmlinux_section 의 정보에 따라 Section의 위치를 해보면 다음과 같습니다.

                      가상주소              물리주소
    DRAM          :                     0x88 0000 0000
    0 .head.text  : ffff000010080000    0x88 1008 0000 
    1 .text       : ffff000010081000    0x88 1008 1000 
   11 .init.text  : ffff000011120000    0x88 1112 0000

    stext         : ffff000011120000    0x88 1112 0000

Clone this wiki locally