[x86] 스터디때 나왔던 cpu_dev 문제

pororo 2012.02.19 14:08 조회 수 : 18429

<arch/x86/kernel/cpu/common.c>

void __init early_cpu_init(void)
    const struct cpu_dev *const *cdev;
...
    for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) {
        const struct cpu_dev *cpudev = *cdev;

여기서 cdev가 가리키는게 무엇인가가 문제였는데 cdev는 말씀하신대로 2중 포인터가 맞습니다.

2중포인터라면 중간에 경유하는 주소 테이블이 있어야 하지 않은가? 하는게 의문이었습니다.

cdev는 cpu_dev 구조체를 가리키는 const 포인터를 가리키니 결국 크기는 포인터형입니다.

64비트의 포인터형이니 cdev++를 하면 값은 8이 증가될 것입니다.

 __x86_cpu_dev_start는 arch/x86/kernel/vmlinux.lds.S 에 있습니다.

    .x86_cpu_dev.init : AT(ADDR(.x86_cpu_dev.init) - LOAD_OFFSET) {
        __x86_cpu_dev_start = .;
        *(.x86_cpu_dev.init)
        __x86_cpu_dev_end = .;
    }

.x86_cpu_dev.init 섹션을 모아주는 매크로는 arch/x86/kernel/cpu/cpu.h 에 있습니다.

#define cpu_dev_register(cpu_devX)
    static const struct cpu_dev *const __cpu_dev_##cpu_devX __used
    __attribute__((__section__(".x86_cpu_dev.init"))) =
    &cpu_devX;

&로 넣어주니 .x86_cpu_dev.init에는 포인터가 들어갑니다.
저는 이 부분에서 구조체 주소가 아니라 구조체 내용이 그대로 들어간다고 착각했었습니다.
__x86_cpu_dev.init은 각 cpu 의 cpu_dev 구조체 주소가 모인 섹션입니다.

<arch/x86/kernel/cpu/Makefile>

obj-$(CONFIG_CPU_SUP_INTEL)        += intel.o
obj-$(CONFIG_CPU_SUP_AMD)        += amd.o
obj-$(CONFIG_CPU_SUP_CYRIX_32)        += cyrix.o
obj-$(CONFIG_CPU_SUP_CENTAUR)        += centaur.o
obj-$(CONFIG_CPU_SUP_TRANSMETA_32)    += transmeta.o
obj-$(CONFIG_CPU_SUP_UMC_32)        += umc.o

<.config>

CONFIG_CPU_SUP_INTEL=y
CONFIG_CPU_SUP_AMD=y
CONFIG_CPU_SUP_CENTAUR=y

<intel.c> 마지막 부분에는 위 매크로로 등록하는 부분이 있습니다.
cpu_dev_register(intel_cpu_dev);

<amd.c>
cpu_dev_register(amd_cpu_dev);

<centaur.c>
cpu_dev_register(centaur_cpu_dev);

ld 스크립트에 의해 포인터가 모였습니다. 확인을 해보겠습니다.

/usr/src/linux/arch/x86/boot/compressed# objdump -h vmlinux.bin

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
....
  3 .rodata       000f7052  ffffffff81400000  0000000001400000  00600000  2**6
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
...
  11 __init_rodata 00003e70  ffffffff81530490  0000000001530490  00730490  2**4
                  CONTENTS, ALLOC, LOAD, READONLY, DATA
...
 20 .x86_cpu_dev.init 00000018  ffffffff81702370  0000000001702370  00b02370  2**3
                  CONTENTS, ALLOC, LOAD, READONLY, DATA

사이즈는 0x18 = 24바이트네요.

/usr/src/linux/arch/x86/boot/compressed# objdump vmlinux.bin -s -j .x86_cpu_dev.init

vmlinux.bin:     file format elf64-x86-64

Contents of section .x86_cpu_dev.init:
 ffffffff81702370 30395381 ffffffff 903b5381 ffffffff  09S......;S.....
 ffffffff81702380 f03d5381 ffffffff                    .=S.....

리틀엔디안이니 뒤집어서 ff ff ff ff 81 53 39 30, ff ff ff ff 81 53 3b 90, ff ff ff ff 81 53 3d f0 를 찾아가겠습니다..

위쪽에 81530490부터 81534300까지는 __init_rodata 영역에 속하네요.

/usr/src/linux/arch/x86/boot/compressed# objdump -s -j __init_rodata vmlinux.bin|grep 81533930
 ffffffff81533930 cb644b81 ffffffff c4644b81 ffffffff  .dK......dK.....

구조체를 찾아보겠습니다.

<arch/x86/kernel/cpu/cpu.h>
struct cpu_dev {
    const char    *c_vendor;

    /* some have two possibilities for cpuid string */
    const char    *c_ident[2];
....
}


<intel.c>
static const struct cpu_dev __cpuinitconst intel_cpu_dev = {
    .c_vendor    = "Intel",
    .c_ident    = { "GenuineIntel" },
....
}


ff ff ff ff 81 4b 64 cb는 .rodata 섹션에 있네요.

/usr/src/linux/arch/x86/boot/compressed# objdump -s -j .rodata vmlinux.bin|grep 814b64c0
 ffffffff814b64c0 38290a00 47656e75 696e6549 6e74656c  8)..GenuineIntel

*c_vendor와 *c_indent 문자열이 동일하니 같은 주소를 재활용하네요. gcc는 똑똑한것 같습니다.

c_ventor는 814b64cb번지로 "Intel", c_ident는 814b64c4번지로 "GenuineIntel"이 됩니다.

간단히 그림으로 그려봤습니다.

cpu_dev_struct.jpg
번호 제목 글쓴이 날짜 조회 수
공지 [공지] 커널 스터디 관련 Q&A 게시판 입니다. [5] woos 2016.04.09 2194
1745 setup.c 파일의 cacheid_init 함수 [1] file HyunGyu 2013.11.05 72265
1744 Vol.1의 CMPS ~ CVTPD2PS 입니다. 늦어서 죄송합니다. file 지현구 2007.03.10 64200
1743 as86(1) - Linux man page 입니다. 김민석 2010.04.30 36679
1742 lilo.c에서 !! 관한 토론? [6] 오시리스 2011.07.25 34354
1741 [ARM중] 1차 분석 복습 [5] file 홍문화 2011.08.08 33707
1740 ZONE_DMA, ZONE_NORMAL, ZONE_HIGHMEM (미완성) 구본규 2013.10.15 32768
1739 fork() 함수가 리턴을 두번하는 이유 설명 [2] 커널B조 2016.05.07 30223
1738 task_struct 구조체입니다. [1] file 아폴로 2013.04.30 29853
1737 ARM 프로세서 모드 [7] 홍문화 2011.06.08 26499
1736 BIOS 를 통하여 PCI configuration space를 액세스하는 방법 지현구 2007.08.12 22864
1735 파이프라인과 익셉션의 관계 관련 블로그 주소입니다. 이한울 2012.05.26 22081
1734 buildroot 사용법 [1] 구본규 2012.07.20 20240
» [x86] 스터디때 나왔던 cpu_dev 문제 [2] file pororo 2012.02.19 18429
1732 페이지 테이블에 주소 변환 정보가 채워지는 원리 [16] 홍문화 2011.07.12 16325
1731 odroid bootlog 입니다 박장운 2010.08.14 15560
1730 명령어 정리 - 늦어서 죄송.. 송형주 2007.03.09 14524
1729 Linux booting 과정 (start_kernel() 함수 전까지) 관련 참고자료들 모음 file 지현구 2007.04.27 14328
1728 분석 환경 구축 실습 [11] file 권석민 2013.05.19 14204
1727 [x86] 가족번호 [2] pororo 2012.02.27 13912
1726 LVM에 대해 간략하게 정리했습니다. [2] file 조성진 2013.05.07 13825
XE Login