본문 바로가기

리눅스 커널의 구조와 원리/2. 라즈베리 파이 설정

[라즈베리파이] 커널 정보 확인 - Trace32

아래 Trace32 스크립트를 실행하면 라즈베리파이 커널 vmlinux를 Trace32에 올릴 수 있습니다.
sys.cpu cortexa7
sys.u
 
d.load.elf vmlinux
 
라즈베리파이 리눅스 커널 정보를 확인하겠습니다.
각 섹션 정보는 아래와 같습니다.
y.l.sec
_____address________|path\section___________________________|acc|init|physical
P:80008000--8000826B|\\vmlinux\.head.text                   |R-X|L-  |
P:80100000--80707797|\\vmlinux\.text                        |R-X|L-  |
P:80707798--807077B3|\\vmlinux\.fixup                       |R-X|L-  |
D:80800000--809C2C83|\\vmlinux\.rodata                      |RW-|L-  |
D:809C2C88--809C91AF|\\vmlinux\__bug_table                  |RW-|L-  |
D:809C91B0--809D0AC7|\\vmlinux\__ksymtab                    |R--|L-  |
D:809D0AC8--809D71FF|\\vmlinux\__ksymtab_gpl                |R--|L-  |
D:809D7200--809DAE8B|\\vmlinux\__kcrctab                    |R--|L-  |
D:809DAE8C--809DE227|\\vmlinux\__kcrctab_gpl                |R--|L-  |
D:809DE228--809FF435|\\vmlinux\__ksymtab_strings            |R--|L-  |
D:809FF438--80A007AB|\\vmlinux\__param                      |R--|L-  |
D:80A007AC--80A00FFF|\\vmlinux\__modver                     |R--|L-  |
D:80A01000--80A01F1F|\\vmlinux\__ex_table                   |R--|L-  |
D:80A01F20--80A36E9F|\\vmlinux\.ARM.unwind_idx              |R--|L-  |
D:80A36EA0--80A86443|\\vmlinux\.ARM.unwind_tab              |R--|L-  |
P:80A86444--80A86467|\\vmlinux\.notes                       |R-X|L-  |
P:80B002E0--80B42A3B|\\vmlinux\.init.text                   |R-X|L-  |
P:80B42A3C--80B43EF7|\\vmlinux\.exit.text                   |R-X|L-  |
D:80B43EF8--80B44133|\\vmlinux\.init.proc.info              |R--|L-  |
D:80B44134--80B44203|\\vmlinux\.init.arch.info              |R--|L-  |
D:80B44204--80B44213|\\vmlinux\.init.tagtable               |R--|L-  |
D:80B44214--80B52FFB|\\vmlinux\.init.smpalt                 |R--|L-  |
D:80B52FFC--80B538A3|\\vmlinux\.init.pv_table               |R--|L-  |
D:80B54000--80B76B93|\\vmlinux\.init.data                   |RW-|L-  |
D:80B77000--80B7D3FF|\\vmlinux\.data..percpu                |RW-|L-  |
D:80C00000--80C798E3|\\vmlinux\.data                        |RW-|L-  |
D:80C7A000--80C7AFFF|\\vmlinux\.data..page_aligned          |RW-|L-  |
D:80C7B000--80D3B9A3|\\vmlinux\.bss                         |RW-|--  |
P:FFFF0000--FFFF001F|\\vmlinux\.vectors                     |R-X|L-  |
P:FFFF1000--FFFF12BF|\\vmlinux\.stubs                       |R-X|L-  |
 
리눅스 버젼은 4.9.80-v7입니다.
v.v % linux_banner 
  (static char [188]) linux_banner = "Linux version 4.9.80-v7+ (austin.kim@LGEARND7B16) (gcc version 4.8.3 20140303 (prerelease) (crosstool-NG linaro-1.13.1+bzr2650 - Linaro GCC 2014.03) ) #1 S
 
_text 즉 전원을 키면 처음 실행되는 스타트업 코드 주소는 0x80008000입니다.
NSR:80008000|EB042DB6___text:____bl______0x801136E0_______;___hyp_stub_install
NSR:80008004|E10F9000            mrs     r9,cpsr
NSR:80008008|E229901A            eor     r9,r9,#0x1A      ; r9,r9,#26
NSR:8000800C|E319001F            tst     r9,#0x1F         ; r9,#31
NSR:80008010|E3C9901F            bic     r9,r9,#0x1F      ; r9,r9,#31
NSR:80008014|E38990D3            orr     r9,r9,#0xD3      ; r9,r9,#211
NSR:80008018|1A000004            bne     0x80008030
NSR:8000801C|E3899C01            orr     r9,r9,#0x100     ; r9,r9,#256
NSR:80008020|E28FE00C            adr     r14,0x80008034
NSR:80008024|E16FF009            msr     spsr_cxsf,r9
NSP:80008028|E12EF30E            dcd     0xE12EF30E
NSP:8000802C|E160006E            dcd     0xE160006E
NSR:80008030|E121F009            msr     cpsr_c,r9
 
Calling Convention
1. start_kernel 함수 호출 전 스택 주소가 0xD000C000라고 가정합니다. 또한 강제로 R14 링크드 레지스터를 __irq_svc 심볼로 설정합니다.
 
[1]: 스택에 {r4-r12,r14,pc} 레지스터를 푸쉬하며 이 동작 스택 주소는 0xD000BFD4로 변경됩니다.
[2]: 스택 주소가 D000BFB8 = (0xD000BFD4 - 0x1C) 로 업데이트됩니다.
NSR:80B00970|E1A0C00D  start_kernel:    cpy     r12,r13
NSR:80B00974|E92DDFF0                   push    {r4-r12,r14,pc} // <<--[1]
NSR:80B00978|E24CB004                   sub     r11,r12,#0x4     ; r11,r12,#4
NSR:80B0097C|E24DD01C                   sub     r13,r13,#0x1C    ; r13,r13,#28  // <<--[2]
 
스택 덤프
_____address|_data________|value_____________|symbol
NSD:D000BFB0| 00 00 00 00  0x0
NSD:D000BFB4| 00 00 00 00  0x0
NSD:D000BFB8| 00 00 00 00  0x0        // <<--[2]     
NSD:D000BFBC| 00 00 00 00  0x0
NSD:D000BFC0| 00 00 00 00  0x0
NSD:D000BFC4| 00 00 00 00  0x0
NSD:D000BFC8| 00 00 00 00  0x0
NSD:D000BFCC| 00 00 00 00  0x0
NSD:D000BFD0| 00 00 00 00  0x0
NSD:D000BFD4| 04 00 00 00  0x4      // <<--[1]           
NSD:D000BFD8| 05 00 00 00  0x5                
NSD:D000BFDC| 06 00 00 00  0x6                
NSD:D000BFE0| 07 00 00 00  0x7                
NSD:D000BFE4| 08 00 00 00  0x8                
NSD:D000BFE8| 09 00 00 00  0x9                
NSD:D000BFEC| 10 00 00 00  0x10               
NSD:D000BFF0| 11 00 00 00  0x11               
NSD:D000BFF4| 00 C0 00 D0  0xD000C000
NSD:D000BFF8| 20 53 70 80  0x80705320         \\vmlinux\Global\__irq_svc
NSD:D000BFFC| 78 09 B0 80  0x80B00978         \\vmlinux\init/main\start_kernel+0x8
NSD:D000C000| 00 00 00 00  0x0
NSD:D000C004| 00 00 00 00  0x0
 
start_kernel에서 set_task_stack_end_magic를 호출할 시 스택에 레지스터를 어떻게 푸쉬하는지 점검합니다.
[1]: 스택 주소는 0xD000BFA8로 업데이트됩니다.
[2]: R12 즉 현재 스택 주소이서 0x4만큼 뻬고 R11에 저장합니다.
NSR:80119F00|E1A0C00D__set_task_stack_end_magic:_____cpy_____r12,r13
NSR:80119F04|E92DD800                                push    {r11-r12,r14,pc}  //<<--[1]
NSR:80119F08|E24CB004                                sub     r11,r12,#0x4     ; r11,r12,#4  //<<--[2]
NSR:80119F0C|E52DE004                                str     r14,[r13,#-0x4]!
 
스택 덤프
_____address|_data________|value_____________|symbol
NSD:D000BF94| 00 00 00 00  0x0
NSD:D000BF98| 00 00 00 00  0x0
NSD:D000BF9C| 00 00 00 00  0x0
NSD:D000BFA0| 00 00 00 00  0x0
NSD:D000BFA4| 00 00 00 00  0x0
NSD:D000BFA8| FC BF 00 D0  0xD000BFFC       // <<--  R11
NSD:D000BFAC| B8 BF 00 D0  0xD000BFB8       //  <<-- R12
NSD:D000BFB0| 88 09 B0 80  0x80B00988         \\vmlinux\init/main\start_kernel+0x18  //<<-- LR
NSD:D000BFB4| 08 9F 11 80  0x80119F08         \\vmlinux\fork\set_task_stack_end_magic+0x8  //<<-- PC
NSD:D000BFB8| 00 00 00 00  0x0
NSD:D000BFBC| 00 00 00 00  0x0
NSD:D000BFC0| 00 00 00 00  0x0
NSD:D000BFC4| 00 00 00 00  0x0
NSD:D000BFC8| 00 00 00 00  0x0
NSD:D000BFCC| 00 00 00 00  0x0
NSD:D000BFD0| 00 00 00 00  0x0
NSD:D000BFD4| 04 00 00 00  0x4            
NSD:D000BFD8| 05 00 00 00  0x5            
NSD:D000BFDC| 06 00 00 00  0x6            
NSD:D000BFE0| 07 00 00 00  0x7            
NSD:D000BFE4| 08 00 00 00  0x8            
NSD:D000BFE8| 09 00 00 00  0x9            
NSD:D000BFEC| 10 00 00 00  0x10           
NSD:D000BFF0| 11 00 00 00  0x11           
NSD:D000BFF4| 00 C0 00 D0  0xD000C000
NSD:D000BFF8| 20 53 70 80  0x80705320         \\vmlinux\Global\__irq_svc
NSD:D000BFFC| 78 09 B0 80  0x80B00978         \\vmlinux\init/main\start_kernel+0x8
NSD:D000C000| 00 00 00 00  0x0
 
위 정보를 종합하면 함수 호출 시 아래 규칙으로 스택에 푸쉬합니다.
[1]: 스택을 푸쉬할 때의 함수 프로그램 카운터
[2]: 호출한 함수(Linked Register) 주소
[3]: 업데이트하기 직전의 스택 주소
[4]: 프레임 포인터 레지스터: 이 주소에 -4를 빼면 바로 이전에 수행됐던 함수 심볼 정보가 보임      
   예를 들면 0xD000BFF8 =  0xD000BFFC - 0x4
 
#스택 덤프
NSD:D000BFA8| FC BF 00 D0  0xD000BFFC       // <<--  [4]
NSD:D000BFAC| B8 BF 00 D0  0xD000BFB8       //  <<-- [3]
NSD:D000BFB0| 88 09 B0 80  0x80B00988         \\vmlinux\init/main\start_kernel+0x18  //<<-- [2]
NSD:D000BFB4| 08 9F 11 80  0x80119F08         \\vmlinux\fork\set_task_stack_end_magic+0x8  //<<-- [1]
NSD:D000BFB8| 00 00 00 00  0x0  //<<-- 스택 주소
// .. 생략..
NSD:D000BFF4| 00 C0 00 D0  0xD000C000
NSD:D000BFF8| 20 53 70 80  0x80705320         \\vmlinux\Global\__irq_svc
NSD:D000BFFC| 78 09 B0 80  0x80B00978         \\vmlinux\init/main\start_kernel+0x8
NSD:D000C000| 00 00 00 00  0x0