A 8월 3일 후기[Rev.2 초록색부분]

HyunGyu 2013.08.04 21:04 조회 수 : 3448

수정 했습니다.

 

Rev.1

초안

Rev.2

Rev.2라고 적힌 부분

2. ownt_overwrite 추가

 

 

 

후기 입니다.

 

이기환님처럼 잘 쓰지는 못할거 같지만....;;;

 

어쨌든 시작합니다~

 

이번 스터디는 크게 두가지를 하였습니다.

 

cache_clean_flush와 wont_overwrite 입니다.

 

이 두가지를 간단하게 살펴보도록 하겠습니다.

 

1. cache_clean_flush

 

1-1. __armv7_mmu_cache_flush 호출

 

/* Preserve offset to relocated code. */
	    sub r6, r9, r6 @@ 압축이 풀려있을 주소공간과 겹치고 있기 때문에 
                        @@ zImage 를 위로 올리기 위해 offset 을 구한다. 

#ifndef CONFIG_ZBOOT_ROM
     /* cache_clean_flush may use the stack, so relocate it */
     add sp, sp, r6 @@ stack 을 위로 올려준다  
#endif

    bl cache_clean_flush @ code 의 주소가 달라졌으므로 cache 를 flush 해줘야 한다.

    adr r0, BSYM(restart) @ 바뀐 code(r6을 더함) 의 restart 의 주소를 r0 에 저장 
    add r0, r0, r6
    mov pc, r0


호출 부분 입니다.

 

bl cache_clean_flush에서 flush를 진행 하도록 하죠.

 

그리고 다음과 같은 일을 하여 진행됩니다.

(해당 내용은 이미 자세히 알거 같아서 그림으로 대처합니다.)

 

plant1.png

 

1-2. __arm7_mmu_cache_flush 진행

 

1-2-1. Hierarchical 인지 확인

 

__armv7_mmu_cache_flush:
      mrc	p15, 0, r10, c0, c1, 5	@ read ID_MMFR1
      tst	r10, #0xf << 16		@ hierarchical cache (ARMv7)
      mov	r10, #0
      beq	hierarchical
      mcr	p15, 0, r10, c7, c14, 0	@ clean+invalidate D
      b	iflush

 

ID_MMFR1을 r10에 얻어 와서 hierachical인지 확인하는 부분입니다.

 

hierachical이란건 다중으로 캐쉬가 있는걸 말하는거 같습니다.

 

L1, L2 캐쉬가 있다면 L1에 있는 내용을 모두 L2에 flush를 하고

그 이후에 L2에 있는 내용을 다시 메모리에 flush를 단계적으로 해야 하기 때문에

hierachical 인지 확인 하는 것이죠.

 

1-2-2. 캐쉬 총 개수 계산

 

hierarchical:
      mcr	p15, 0, r10, c7, c10, 5	@ DMB
      stmfd	sp!, {r0-r7, r9-r11}
      mrc	p15, 1, r0, c0, c0, 1	@ read clidr
      ands	r3, r0, #0x7000000	@ extract loc from clidr
                                          @@ flush 해줘야 할 클린 레벨
      mov	r3, r3, lsr #23		@ left align loc bit field
                                  @@ r3 = loc * 2
      beq	finished		@ if loc is 0, then no need to clean


DMB를 하고

TODO: 이건 정확하게 무얼 하는 건지 알아봐야 한다.

 

clidr을 읽어 loc 영역에서 캐쉬의 최종 개수가 어떻게 되는지 알아 보는거 같아 보입니다.

 

clidr.png

ands r3, r0, #0x7000000을 하여 r3에 loc 영역만 남겨 놓고

 

mov r3, r3, lsr #23 을 하는데..

 

이 부분에서 봐야 하는건..

 

실제 loc는 24번째 비트에 있다는 것이죠..

 

23비트 만큼 우로 시프트를 하게 되면 0비트에 바로 붙지 않고 1비트에 붙는다는 것인데

 

이건 loc에 곱하기 2 한 효과가 있습니다..

 

이런게 이 후에 어떻게 사용될 것인가는 과제로 남기겠습니다.

 

1-2-3. 캐쉬에 대한 정보 얻기

 

      mov	r10, #0			@ start clean at cache level 0 
 loop1:
		      add          r2, r10, r10, lsr #1    @ work out 3x current cache level
                                                     @@r2는 loop1을 돌때마다 3씩 증가
      mov          r1, r0, lsr r2          @ extract cache type bits from clidr
      and          r1, r1, #7              @ mask of the bits for current cache only
        @@ +------+---------+
        @@ |00    |no       |
        @@ |      |cache    |
        @@ +------+---------+
        @@ |01    |icache   |
        @@ +------+---------+
        @@ |10    |data     |
        @@ |      |cache    |
        @@ +------+---------+
        @@ |11    |I/D Cache|
        @@ +------+---------+
      cmp	r1, #2			@ see what cache we have at this level
                                                
      blt	skip			@ skip if no cache, or just i-cache
      mcr	p15, 2, r10, c0, c0, 0	@ select current cache level in cssr
      mcr	p15, 0, r10, c7, c5, 4	@ isb to sych the new cssr&csidr
      mrc	p15, 1, r1, c0, c0, 0	@ read the new csidr
      and	r2, r1, #7		@ extract the length of the cache lines
      add	r2, r2, #4		@ add 4 (line length offset)
      ldr	r4, =0x3ff
      ands	r4, r4, r1, lsr #3	@ find maximum number on the way size
      clz	r5, r4			@ find bit position of way size increment
      ldr	r7, =0x7fff
      ands	r7, r7, r1, lsr #13	@ extract max number of the index size

 

 

r10에 0을 넣어 첫번째 캐쉬부터 캐쉬의 정보를 얻으려고 하는거죠.

 

후에 r10에 2씩 더하기를 해서 다음 캐쉬 정보를 얻게 하는데.

 

왜 2를 더하는지는....

이것 역시 수수께끼로 남겨 두겠습니다....^^;;;

(모르는데 이런 말씀을 드리는거 아닙니다!!ㅋㅋㅋ)

 

add          r2, r10, r10, lsr #1
 mov          r1, r0, lsr r2
 and          r1, r1, #7

우선 위에 세 줄을 보면...

 

r1에 r10값에 1.5를 곱해서 clidr에서 필요한 Ctype 값을 넣는다. 가 최종 목적입니다.

 

이 말인 즉슥... r10이 0이면 그림의 Ctype1을 가져 와서 and 연산으로 나머지는 지우고..

 

r10이 2일 때(제가 2씩 증가 한다고 했죠~?) 1.5배를 하면 3이니까 3비트 부터 해서 Ctype2를 가져 와서 and 연산으로 나머지는 제거 하게 되죠.

r10이 4일 때 1.5배를 하면 6이니까 6비트 부터인 Ctype 3을 가져 오는거예요.

 

이렇게 캐쉬에 따라 필요한 Ctype을 r1에 넣습니다.

 

그럼 Ctype에는 뭐가 있는가??

 

해당 캐쉬가 icache인지 dcache인지 아니면 둘다인지.. 검사 하여서

icache이면 flush를 할 필요가 없으니(바뀐 내용이 있어야 flush를 할테니까요.^^)

그냥 skip 하게 됩니다.

 

그렇게 하는게 다음 소스였죠.

 

cmp	r1, #2
blt	skip

이 후에 캐쉬에 대한 내용을 csidr을 통해 얻어서 필요한 정보를 얻습니다.

 

여기서 얻는건..

 

LineSize, Associativity(Way 수), NumSets 을 각각 얻게 됩니다.

 

이 부분은 나머지 소스 영역입니다.

 

===Rev.2수정 시작{

 

위에 부분을 계속 읽다 보니.. 부족하다는 느낌이 너무 많이 들어서 조금 수정합니다.;;

 

일단 csidr에 대한 그림을 보면 아래와 같습니다.

 

csidr.png

LineSize를 r2에 넣고 4를 더하게 됩니다.

 

4를 더하는 이유는 아래에 알려드리도록 하겠습니다.

 

그리고 r4와 r7에 각각 Associativity와 NumSets의 값을 넣는데..

 

여기서 주석을 보면 최대의 way와 최대 index 라는걸 알 수 있습니다.

 

후에 1씩을 빼면서 전체 way와 전체 index를 flush 하려고 하는 것죠.

 

그리고 처음 보는 명령어인 clz r5, r4 가 나옵니다.

 

이 clz r5, r4는 r4에 31비트부터 처음으로 1이 나오는 비트의 번째수를 구하는 겁니다.

 

예를 들어 r4에 b0000 0000 0000 0010 0000 0000 0000 0000 이라고 한다면...

 

1이 나오기 전에 빨간 0의 개수가 14개 있으니.. r5에는 14가 들어 갈 것입니다.

 

r5는 후에 way 부분을 앞으로 정렬(?) 하는 부분 때문에 필요한 레지스터 입니다.

 

}Rev.2수정 끝===

 

1-2-4. 해당 index에서 way 별로 flush

 

loop2:
		      mov	r9, r4			@ create working copy of max way size
loop3:
ARM(		orr	r11, r10, r9, lsl r5	) @ factor way and cache number into r11
ARM(		orr	r11, r11, r7, lsl r2	) @ factor index number into r11
                                          @@ 메뉴얼 B.4.2.1 SET/WAY 레지스터 모양과 같은 형태를 만들어줌 
      mcr	p15, 0, r11, c7, c14, 2	@ clean & invalidate by set/way
                                             @@ 웨이 안에 있는 한 라인 플러쉬 완료
      subs	r9, r9, #1		@ decrement the way
                                                
      bge	loop3                   @@ 현 웨이에서 - 1 웨이로 진입

 

여기서 알아야 하는건 크게 두개이다.

 

하나는 mcr p15, 0, r11, c7, c14, 2 를 할 때 레지스터의 구조이고

 

cache의 저장 정책인데...

 

일단 clean 할 때 구조를 보자.

 

setandway.png

 

입력할 때의 구조는 위와 같습니다.

 

여기서 필요한 way, set, level 등은 이전에 모두 계산 된 값들이죠.

 

이 값을 위의 형태로 채우기만 하면 됩니다.

 

아~~~주 간단하죠.^^

 

===Rev.2수정 시작{

 

아주 간단하다고 생각했는데...

 

어찌... 조금 복잡할 수 있겠다는 생각에 다시 수정 합니다..^^;;

 

way야 r4가 될 텐데...(r9에 r4를 넣긴 했습니다)

 

아까 제가 앞으로 정렬(?) 해야 한다고 했죠??

 

그래서 r5를 이용해서 시프트 연산을 하여서 orr를 하는 것입니다.

 

그 명령어가

 

 orr r11, r10, r9, lsl r5

 

가 되겠죠..

 

그럼 r10은 먼가 하면... 캐쉬 레벨입니다.

 

지금은 0이니까 아무 값도 들어 가지 않겠지만..

 

후에 2가 되면(제가 2씩 증가 된다고 했었죠???ㅋ) 그럼 2가 입력되게 됩니다.

 

그런데 레벨은 0번째 비트 부터 입력되는게 하니라 1번째 비트 부터 입력되니까..

 

실제로 0번째 비트 부터 보시면... b0010 이라고 입력 되겠죠??

 

r10이 4가 되면... b0100 이 되고요..

 

어때요???

 

r10이 1씩 증가 되었다면 여기서 시프트 연산을 했어야 했는데

2씩 증가하니까 시프트 연산 없이 바로 입력 할 수 있게 되죠?? ^^;;

 

숙제로 내려 했는데.. 제가 답을 알려드렸네요..ㅋㅋ

 

그리고 이제 마지막 set부분인 index를 입력 해야 하는데..

 

이 때 사용하는게  orr r11, r11, r7, lsl r2 명령입니다.

 

r7이야 index고 r2는 LineSize라고 했었죠??

 

이제 LineSize에 왜 4를 더하는지 보이나요??? ^^;

 

Set부분은 LineSize에 따라 저장되는 위치가 다른데

시작 부분은 항상 Level을 입력하고 나서부터 입니다.

 

Level을 입력하는 부분은 총 4비트가 걸리니 그 이후에 Set을 입력해야 겠죠??

 

그러니 LineSize에 4를 더해서 Level 입력 부분 이후 부터 Set을 입력하라고 하는 겁니다.

 

}Rev.2수정 끝===

 

그리고 다음 명령어 부분을 보죠.

 

subs	r9, r9, #1		@ decrement the way
bge	loop3

현재 way 값에서 하나의 값을 줄여서 다음 way를 flush 하는 거죠.

 

이 때 봐야 하는게 캐쉬의 정책인데요...

 

이건 민홍 교수님의 자료를 보도록 하겠습니다.

cache.png

Way의 가장 큰 값이 가장 앞에 그려진 네모라고 보시면..

 

각 Way는 여러 index로 나눠지죠..

 

그림 상으로는 4개의 index겠네요.

 

처음 하게 되면 첫번 째 way에서 첫번째 index만 flush 하게 된거니..

 

way의 값을 하나 줄여서(그 뒤에 있는 way) 다음 way의 첫번째 index만 flush하는 거죠.

 

이렇게 반복을 해서 모든 way의 첫번째 index를 flush를 하면 됩니다.

 

1-2-5. 다음 index를 모두 flush 하고 다음 레벨의 캐쉬도 flush

 

    subs	r7, r7, #1		@ decrement the index
                                                @@ 현 인덱스에서 -1 인덱스로 진입
    bge	loop2 
skip:
      add	r10, r10, #2		@ increment cache number
      cmp	r3, r10
      bgt	loop1                 	@@다음 레벨 캐시로 진입


당연히 위에서 첫번째 index만 flush를 했으니..

 

index 값을 줄이면서 다음 index들을 모두 flush 합니다.

 

이렇게 모든 way, index를 flush 하면 이제 다음 캐쉬로 넘어 갑니다.

 

1-2-6. 마무리

 

finished:
		      ldmfd	sp!, {r0-r7, r9-r11}
      mov	r10, #0			@ swith back to cache level 0
      mcr	p15, 2, r10, c0, c0, 0	@ select current cache level in cssr
iflush:
      mcr	p15, 0, r10, c7, c10, 4	@ DSB
      mcr	p15, 0, r10, c7, c5, 0	@ invalidate I+BTB
      mcr	p15, 0, r10, c7, c10, 4	@ DSB
      mcr	p15, 0, r10, c7, c5, 4	@ ISB
      mov	pc, lr


이 부분은 특별히 설명이 필요가 없을거 같네요.

 

마무리 하는거죠..

 

캐쉬를 모두 정리 하고 다시 return 하는 부분입니다.

 

2. wont_overwrite

 

압축을 풀 때 겹치는 부분이 없다면 해당 레이블로 들어 오게 됩니다.

 

사실 이 wont_overwrite는 크게 봐야 할 곳은 없는거 같습니다.

 

대충~~ 봐도 쉽게 이해 되는게 대부분일거예요..^^

 

그러니 쉽게 넘어 가도록 하겠습니다.

 

2-1. 이미지의 물리 주소와 실행 주소 차이 확인 후 보정

 

    orrs	r1, r0, r5
      beq	not_relocated

      add	r11, r11, r0 @@파일 오프셋과 실제 메모리 주소상의 위치 차이 보정
      add	r12, r12, r0

#ifndef CONFIG_ZBOOT_ROM
		/*
		 * If we're running fully PIC === CONFIG_ZBOOT_ROM = n,
		 * we need to fix up pointers into the BSS region.
		 * Note that the stack pointer has already been fixed up.
		 */
      add	r2, r2, r0 @@BSS 주소도 위치 차이 보정
      add	r3, r3, r0

		/*
		 * Relocate all entries in the GOT table.
		 * Bump bss entries to _edata + dtb size
		 */
                ;; @@재배열된 주소공간을 가르키는 GOT 엔트리 보정 
1:      ldr	r1, [r11, #0]		@ relocate entries in the GOT
      add	r1, r1, r0		@ This fixes up C references
      cmp	r1, r2			@ if entry >= bss_start &&
      cmphs	r3, r1			@       bss_end > entry
      addhi	r1, r1, r5		@    entry += dtb size
      str	r1, [r11], #4		@ next entry
      cmp	r11, r12
      blo	1b

      /* bump our bss pointers too */
      add	r2, r2, r5
      add	r3, r3, r5

 

r0 값(예~~~전에 .LC0로 실제 이미지의 메모리 주소와 수행 중 메모리 차이를 구했죠..)인

값을 이용해서 r0 만큼 차이를 보정 하는 부분입니다.

 

진짜!! 쉽습니다...!!

 

중간에 하나 신경 써야 하는 부분이 있다면...

 

cmp r1, r2 @ if entry >= bss_start &&
cmphs r3, r1 @       bss_end > entry
addhi r1, r1, r5 @    entry += dtb size


이 부분인데..

 

이건 처음에는 이미지의 끝과 bss 영역 사이에는 아무 것도 없었는데..

 

head.S를 진행 하다 보니 중간에 dtb가 추가 되었죠???

 

그러니 bss 영역을 dtb 위쪽에 배치를 해야 하니까 저 명령어 부분이 추가 된거 같습니다.

(이 부분 잘못된거 있으면 알려주세요.^^;;)

 

2-2. BSS 영역 초기화

 

not_relocated:	    mov	r0, #0
1:      str	r0, [r2], #4		@ clear bss
      str	r0, [r2], #4
      str	r0, [r2], #4
      str	r0, [r2], #4
      cmp	r2, r3
      blo	1b

 

딱 봐도.. BSS 초기화 부분 같죠??? ^^;;

 

넘어 가겠습니다.

 

2-3. 압축 풀기

 

mov	r0, r4
		mov	r1, sp			@ malloc space above stack
		add	r2, sp, #0x10000	@ 64k max
		mov	r3, r7
		bl	decompress_kernel       @@ 함수 호출

최종 목적은 decompress_kernel을 호출 하기 위한건데..

 

ABI에 따라 각 레지스터에 필요한 파라미터를 넣고 있습니다.

 

r0, 1, 2, 3인 각각은 커널 실행 주소, stack의 시작, stack의 끝, architecture ID를 넣어서

함수를 호출 합니다.

 

해당 함수는... 별로 중요한게 없어서 넘어가겠습니다~~^^;;

 

2-4. 캐쉬 정리

 

bl	cache_clean_flush // @@ 압축을 해제할때 cache 를 사용했으므로 cache flush 를 해준다. 
		bl	cache_off

압축을 풀 때 사용했던 cache를 모두 정리 하는 것입니다.

 

cache_off 부분은 너~~무 간단해서 넘어가도록 하겠습니다.^^;;;;;

(진짜!! 쉬우니 꼭 한번 보세요~~)

 

2-5. __enter_kernel 호출

 

mov	r1, r7			@ restore architecture number
mov	r2, r8			@ restore atags pointer
b	__enter_kernel

__enter_kernel을 호출하기 위해서 r1과 r2에 필요한 값을 넣습니다.

 

여기서 r0은 어떤걸 입력하는건가?? 라는 질문이 나왔는데...

 

그건 다음 명령어를 보면 알 수 있습니다.

 

2-6. 압축 푼 커널의 시작 부분 호출

 

__enter_kernel:
    mov r0, #0 @ must be 0
 ARM( mov pc, r4 ) @ call kernel @@ kernel 의 시작 주소로 간다. arch/arm/kernel/head.S                                


여기서 r0를 입력하게 되는거죠..^^;

 

그리고 pc에 r4를 넣어서 압축을 푼 커널로 이동을 하는 거죠.

 

 

 

 

이렇게 토요일에 모든 내용을 정리(?) 하였습니다.

 

head.S를 끝내기 위해 막판 15분 동안 cache_off를 끝낸걸 보면 참 대단했다고 생각했습니다.^^

 

 

B팀은 먼저 드라이빙을 정리 하면서 어려운걸 알려주고...

 

C팀에서는 질문 거리를 정리 하고..

 

A팀은 주석 보다 조금 더 자세하게 정리하고..

 

먼가.. 이 세팀이 스타일이 모두 달라서 서로 시너지 효과를 얻고 있는 듯한 느낌입니다.

 

앞으로도~~ 모든 팀들이 서로 힘을 합쳐서 어느 팀도 낙오 하지 말고 모두 목표한 바를 얻었으면 좋겠습니다~^^

 

번호 제목 글쓴이 날짜 조회 수
공지 [공지] 커널 스터디 관련 Q&A 게시판 입니다. [5] woos 2016.04.09 2198
90 setup.c 파일의 cacheid_init 함수 [1] file HyunGyu 2013.11.05 72308
89 vmlinux가 arch/arm/boot/zImage로 변환되는 과정 (그림추가) [1] file K 2013.07.25 11156
88 스터디 시간에 나왔던 ARM 어셈블러 시뮬레이션 방법을 한번 정리해보았습니다. [7] file 코로케 2013.07.02 6860
87 10차 ARM-A팀 8/17 후기는 절 기다리지 마세요 [3] K 2013.08.17 6783
86 ARM Cortex-A 주소변환에 관한 자료 [6] bluesky 2013.07.07 6260
85 Exynos 5410 octa core processor with 2GB RAM, USB 3.0 (주) 하드 커널사. [6] 이찬 2013.08.02 4048
» 8월 3일 후기[Rev.2 초록색부분] [21] file HyunGyu 2013.08.04 3448
83 안드로이드에 무료 git 어플이 생겼네요..^^ [3] HyunGyu 2013.07.10 3153
82 arm10a github 계정을 댓글로 남겨주세요 [43] K 2013.09.14 3088
81 회식 메뉴 정해요~~(장소 예약 했습니다. 강남역 새마을 식당입니다.) [22] file HyunGyu 2013.07.09 2956
80 회식 때 사진 및 인원 소개입니다. [8] file HyunGyu 2013.07.14 2894
79 memory.h파일의 phys_to_virt 함수 file HyunGyu 2013.11.03 2465
78 저희도 주석을 위한 코딩 스텐다드가 필요할 듯합니다. [12] HyunGyu 2013.07.02 2362
77 130713 회식 후기 입니다. [7] HyunGyu 2013.07.14 2203
76 A팀도 아직 합니당.. [3] 이찬 2015.03.11 2120
75 [펌] 팀보다 뛰어난 선수는 없다. [3] K 2013.07.19 2113
74 setup.c 파일의 setup_processor 함수 [5] file HyunGyu 2013.11.03 2043
73 A팀 후기 기다릴게요.^^ [1] HyunGyu 2013.07.21 1660
72 이번주 A팀 수업 참관하고 싶습니다. [2] 리누즈박 2013.08.02 1640
71 [ARM A] 스터디 진도 조절 의견 [2] 이찬 2013.11.22 1591
XE Login