Skip to content

Latest commit

 

History

History
335 lines (271 loc) · 19.1 KB

a10c_11.md

File metadata and controls

335 lines (271 loc) · 19.1 KB

자.. 항상 궁금한 것만 많은 C팀 후기입니다!

이번주는 생각보다 적은 인원이 참여하였습니다. 아마 날씨가 더워서 그렇....겠..죠?^^?

저도 멍하고 있었더니, 정리가 엉망일 수도 있겠네요. 나머지 수정은 댓글로 토론을 해보도록 해요

Kernel 스터디 10차 (ARM C) 바로가기

────────────────────────────────────────────────────────

  1. Revision History 내 용
  • 11주차 이슈 정리    

  • git diff 명령 수정

  • tst 명령 답변 수정

  • eq명령 답변 수정

  • mov r12, lr 명령의 사용이유 답변 수정

  • CONFIG_MMU와 vmsa 동시 체크 관련 답변 수정

  • ARM의 immediate값 연산관련 표현범위 답변 수정

  • memory 시작주소가 0x4000_0000인 이유 답변 수정  

  • git diff 명령 의미 추가

  • device tree 설명 추가

  • device tree 사용방법 추가  

  • exynos 설정방식 답변 수정

  • CONFIG_MMU와 vmsa 체크 관련 답변 추가

  • flash로 부팅 중 B를 다시 on시키는 이유 답변 추가  

  • XN 및 U에대한 설명 추가

  • ATAGS 이슈 자료 추가(8차 ARM 게시판)

  • device tree 자료 링크(9차 ARM 게시판)

  1. Study Contents 11주차 2013.07.06 / 18+2(9차 ARM멤버 참관)명 / 강남토즈타워점(NIPA 지원) / arch/arm/boot/compressed/head.S 분석

다음시간부터 30분정도 remind 시간을 갖는 것이 좋겠다. 효율적인 분석을 위해서 역할을 분담하자. 메인 MC 지정: 허욱님 or 신기화님 소스 드라이빙: 박영기님 → 김성학님 → 손정희님 Team 1: 구글링+모기향책 분석 Team 2: Reference Manual 검색 장소예약: 김성학님 소스 드라이빙: 박영기님 & 김성학님 사진촬영: 김성학님 식사: 한방삼계탕(반계탕: 6,500원, 한방반계탕: 7,000원)

  1. Issues

11주차(2013.07.06)

오늘부터 3.10으로 분석하기로 하였는데, 업데이트 방법을 알려주세요. (빠지신 분들 필독!) #git remote -v               @ 올바른 주소인지 체크 #git pull origin               @ 자동으로 patch하여 merge까지 함 #git branch                @ local이 어디에 있는지, 어디 붙어있는지 알 수 있음 #git checkout -b master orogin/master    @ master branch 받아옴 #git branch -vv               @ 현재 local이 어디랑 붙어있는지 알 수 있음 #git log                  @ 변경사항 확인 가능 그럼 이제 3.10으로 분석하는데, 우리가 진행했던 head.S는 변경사항이 없나요? git diff를 이용하여 변경사항을 확인 가능합니다. git diff [] {0,2} [..] […]

다음의 명령으로 변경 내용을 확인 가능합니다. #git diff v3.9.6..8bb495e arch/arm/boot/compressed/head.S

일단 위 명령의 의미는요 v3.9.6 태그로부터..8bb495e커밋까지의 변경사항 중에서 arch/…/head.S 파일의 변경내용만 보여달라는 명령입니다.

이떻게 이 명령이 만들어졌냐면

우리가 작업하던 버전에 v3.9.6이었으니까 먼저 태그가 있는지 확인해 봅니다. git tag | grep v3.9.6

태그가 있으면 v3.10의 커밋을 찾습니다. 이건 태그가 안붙어있어서 sha-1해시를 찾는겁니다. git checkout master git log –oneline –abbrev-commit

566ce8e 레퍼런스 매뉴얼 추가 04f07ed 2013/07/06 a8054cc 2013-06-22 ~ 2013-06-29 8bb495e Linux 3.10

둘 다 찾았으니까 위 명령으로 둘 사이의 차이를 이렇게 봅니다. git diff v3.9.6..8bb495e arch/arm/boot/compressed/head.S index 9109ebe..00a5490 100644 --- a/arch/arm/boot/compressed/head.S +++ b/arch/arm/boot/compressed/head.S @@ -905,8 +905,8 @@ call_cache_fn: adr r12, proc_types .align 2 .type proc_types,#object proc_types: - .word 0x00000000 @ old ARM ID - .word 0x0000f000 + .word 0x41000000 @ old ARM ID + .word 0xff00f000 mov pc, lr 이제 다시 cache 분석 하려고 하는데, write-through와 write-back의 차이점이 나온다. 이게 뭐였지? write-through는 cache와 memory에 값을 전부 기록하는 것을 말한다. 이 방식은 cache와 memory간에 data가 항상 일치하는 장점은 있지만, 매번 memory에 써야 하기 때문에 속도가 느리다.

속도를 개선하기 위해서 나온 방식이 write-back이다. write-back은 연산을 할때는 cache에만 값을 저장하면서 처리하고, cache에서 그 값을 빼야할때 memory에 저장하는 방식이다. (data의 사용빈도가 낮아짐-LRU정책, 기타 다른이유) 이 방식은 속도는 빠르지만 cache와 memory의 값이 달라서 Inconsistency하고, 특히 multicore에서 이슈가 되었었다.

C팀은 똑똑하셔서 전부 이해하셨을 거라 생각하지만, 혹시 헷갈리는 분이 있을까 하여 1가지 예만 들어보겠습니다.

회사에서 백창우 상사가 바구니 안에 동전이 몇개 있는지 세어오라고 일을 시켰습니다. 제 책상과 백창우 상사의 책상 거리는 10미터 입니다. (내책상=cache, 백창우 상사 책상=memory) 근데 동전 1개 세고, 백창우 상사의 책상으로 가서 바구니의 동전을 1개 세었다고 보고합니다. 그리고 2개째 세면, 다시 가서 2개 세었다고 보고 합니다. (Write-Through) 이렇게 하다보니까, 동전을 세는 시간보다 가서 보고하는 시간이 더 오래 걸리고, 귀찮아서 막 짜증이 납니다.

그래서 일단 바구니의 동전을 제 책상에서 전부 세었고 12,862개가 있는걸 알았습니다. (세는동안 나와 백창우 상사가 알고 있는 동전의 개수는 다름 = Inconsistency) 동전을 다 세고나서 다른 작업을 하려고 보니까, 오늘 여자친구 만나서 데이트할 코스도 몰래 생각해야 하고 프로그램 작업도 조금 남아 있어서, 제 머리속에는 동전개수를 기억할 여지가 없습니다. (동전개수=victim) 그래서 제가 센 동전 개수를 백창우 상사에게 가서 보고하고, 전 다른일을 합니다. (Write-Back) tst 명령과 zeroflag 사이의 관계가 계속 헷갈린다. tst r1, r2의 명령을 통해 r1 & r2 의 결과가 0이면, CPSR.Z =1 이 set되고, 1이면(다르면), CPSR.Z = 0 이 설정된다. 뒤에 붙는 eq명령도 계속 혼란스럽다. CPSR.Z = 1 이면, 해당 명령어를 실행하는 것이다. 그럼 CPSR.Z = 1을 한번 설정해두고, 뒤에서도 계속 사용할 수 있나? 뭐 그렇기는 하지만, 보통 연산할때 다시 CPSR.Z 비트를 업데이트 하고 사용한다. 자신의 코드에서는 cpsr의 플래그의 변화를 예측할 수 있지만, 펑션을 호출하는 경우, 그 플래그가 어떻게 바뀔지 예측 할 수 없다. 인터럽트의 경우 현재 cpsr를 따로 spsr에 저장했다고 복귀시에 복원하므로 문제없다. mov r12, lr을 자꾸 사용하는데, 이건 왜 그런 것이냐? stack을 사용하지 않기 때문이다. stack을 현재 사용하지 않는 이유는, register가 현재 충분하여 속도를 높이기 위해서 그렇다. 현재 코드에서 스택을 이용하려 하면, 그 위치를 잡기가 곤란할 것이다. 커널 압축이 해제되면서 스택영역을 침범할 수 있는 경우를 피하기 위해, 스택을 사용하지 않을 수 있다면 그러는 편이 현재는 유리할 것이다. 저번주 게시판에서 DT(Device Tree)를 언급하였는데, 이건 무엇이냐? 예전에는 device마다 kernel을 따로 지원해서 노가다가 심했는데, 요즘은 kernel을 따로 만들어서 DT를 따로 운영하면 매번 빌드할 필요가 없어졌다. 이제 DT를 지원하면, 가져다가 모든 시리즈를 커버할 수 있는 장점이 존재한다. DT를 사용하면 커널 이미지가 특정 하드웨어를 위해 따로 빌드할 필요가 없어진다. 커널을 빌드 할 때는 각각 CPU별로 커널 컴파일하는 설정 파일들이 별도로 존재하고 그에 따라서 커널 이미지가 만들어진다. zImage나 uImage를 커널 바이너리 이미지에 넣도록 빌드를 하고 각 타겟별로 Device Tree Blob만 바꿔주면, 각각의 타켓 보드에 맞는 부팅이 가능해진다. 즉 Architecture별로 빌드하여 배포되는 최신 커널 이미지를 바로 이용할 수 있게 된다.

Flattened Device Tree (9차 ARM) 그럼 실제로 DT를 어떻게 사용 하는 것이냐? kernel config에서 DT를 사용할 수도 있고, 기존의 ATAGS를 사용할 수 있다. (CONFIG로 설정) ATAGS 이슈 자료 (ARM 8차 멤버들) Kernel parameters

u-boot의 경우, 부트로더에서 커널 이미지 (zImage나 uImage), 램디스크 (initramfs) 그리고 Device Tree Blob (예를 들면 exynos.dtb)를 먼저 메모리로 로딩을 한 후 u-boot의 ‘bootm’ 명령으로 부팅을 한다. 커널이 부팅을 되면서 디바이스트리를 읽어들이고 필요한 드라이버를 차례대로 하나씩 하나씩 초기화하기 시작한다. 게시판을 통해서 exynos 5440 설정 방식을 설명해 주었다. 그런데, 우리가 하기로 한것은 5410아닌가? 삼성에서 올리는 github를 보면 5250과 5440을 볼 수 있고, 최근에는 5420이 올라오고 있다. https://git.kernel.org/cgit/linux/kernel/git/kgene/linux-samsung.git/ kernel tree는 왜 그렇게 분리해서 가나요? 버전이 여러개가 있는데, 토발즈만 해도 mainline, stable, longterm 등이 존재한다. 또한 여기서 갈라져 나온 tree들이 많다. 그러면 우리는 지금 exynos 5410을 타겟으로 하고 있는데, samsung git을 봐야 하는거 아니냐? 여기는 삼성 전용만 개발하고, 나중에 mainline으로 merge한다. 변경 내용은 메일링 리스트를 확인하면 볼 수 있다. (여러개 존재 하는데, 그나마 편한곳이 markmail.org이다.) 메일링 리스트를 검색하면 버그 같은것도 확인 가능하다. 자 이제 소스코드 분석으로 돌아가자. 아래 code를 보면, __setup_mmu 에서 config_MMU라면 VMSA를 지원한다는 얘기인데 왜 체크 코드가 또 존재할까? __armv7_mmu_cache_on:

#ifdef CONFIG_MMU

@ VMSA

@ !XN

__setup_mmu CONFIG_MMU이면서 VMSA가 support 되지 않는 경우가 있는지 알아봐야 할 것 같습니다.

MMU는 가상메모리를 위해 있기때문에 그런 경우는 없을 것으로 보입니다. 체크코드가 있는 이유는 COFIG_MMU 설정됐지만, CONFIG는 임의로 설정 가능하기 때문에 실제 MMU가 있는지 확인차원에서 Coprocessor를 통해서 확인하는 것 같아요. 아래 code에서 왜 bic 연산을 2번할까??? 그냥 1번에 다 처리하면 안되는 것인가? 다음에 나오는 mov 연산도 그렇다. @ Page directory size @ Align the pointer r3, r3, #0x3f00

    ...

@ start of RAM ARM A5.2.4를 보면, ARM의 immediate값 연산은 다음과 같이 나타나 있다.

총 32bit중에 shift연산할 수 있는 4bit와, 수치를 나타내는 8bit로 제한되어 있어서, 표현의 범위가 제한되어 있어서 그렇다. 그렇다면 왜 저렇게 설계해 놓은것인가? Instruction을 다 만들고 남은게 저거 밖에 안남아서 이렇게 한거다. 남은 12비트로 최대한 활용을 높이려고 이렇게 구조를 만든것 같다. 12비트 값 보다는 8비트+4비트 쉬프트 구조가 더 많은 경우에 활용될 수 있다. mov rd, #imm 명령에도 이와 같은 제약이 있다. 좋다. 근데 위에서는 저렇게 bic를 이용하더니 왜 밑에서는 mov를 이용한 shift연산을 하는가? 이건 알아봐야 할것같다.(근데 적다보니까.. 참 호기심이 많은 팀이긴 하네요^_^;) FIXME RAM의 시작주소 설정시, 하위 bit를 클리어 하는 이유는? 보통은 size에 완전히 align해서 만들기 때문에, datasheet를 보면 될 것이다. 막상 확인해 보니 , 0x2000_0000 로 존재하여 이상하다고 여김.

mach-exynos/include/mach/memory.h를 보면, PLAT_PHYS_OFFSET에 0x40000000가 정의되어 있다.

mach-exynos/include/mach/map.h (Memory map definitions) 에 보면 #define EXYNOS5_PA_SDRM 0x40000000 로 정의 되어 있다. 아래 코드에서 XN은 대체 뭐냐? @ XN|U + section mapping r1, r1, #3 << 10 @ AP=11

ARM B.3.5.1을 보여주면 다음과 같은 register를 확인할 수 있다.

여기서 XN(0x10)은 코드 영역이 아니라는 것을 알려준다. XN, Execute never (ARM B.3.7.2) When the XN bit is 1, a Permission fault is generated if the processor attempts to execute an instruction fetched from the corresponding memory region. 좋다. 그럼 U는 뭐냐?? 아래는 Russell king의 commit 내용이다.

git log 1fdc08ab

—————————————————————– commit 1fdc08abfa26f30fcef0ce1333e9ac6f80350f30 Author: Russell King rmk+kernel@arm.linux.org.uk Date: Thu May 10 09:48:34 2012 +0100

ARM: decompressor: avoid speculative prefetch from non-RAM areas

We setup identity MMU mappings across the entire 4GB of space, which are permissionless because the domain is set to manager.

This unfortunately allows ARMv6 and later CPUs to speculatively prefetch from the entire address space, which can cause undesirable side effects if those regions contain devices.

As we setup the mappings with read/write permission, we can switch the domain to client mode, and then use the XN bit for ARMv6 and above to control speculative prefetch to non-RAM areas.

Reported-by: R Sricharan r.sricharan@ti.com Acked-by: Santosh Shilimkar santosh.shilimkar@ti.com Signed-off-by: Russell King rmk+kernel@arm.linux.org.uk —————————————————————–

git diff 1fdc08ab 1fdc08ab^ head.S 를 하여 1fdc08ab과 1fdc08ab 바로 이전(^)을 diff해보면 Russell은 주석만 변경했다는걸 확인할 수 있다.

git blame 1fdc08ab^ head.S 를 하여 1fdc08ab 바로 이전(^)의 head.S에 대한 blame을 보면, 그 라인의 Author가 2005년 Linus 이며, 최초 import때부터 존재하였다.

요약하면, 이전에는 퍼미션없이 설정하였는데 ARMv6 이상버전부터 “speculatively prefetch” 때문에 예상하지 못한 문제점이 발생하였고, 그래서 XN비트를 이용하였음 Speculative Prefetching 이란? This scheme detects vector accesses issued by a load/store instruction and prefetches the corresponding data.

여기서 언급하는 U는 allow write to Update the cache 라고 하며, XN은 ARMv6 이후에 나온 것이고, 그전에는 몇가지 용도로 사용하였다. 현재 우리는 ARMv7을 보고 있으니 XN만 숙지하면 되고, 자세한 내용은 아래의 메일링 리스트를 참고 하면 될 것이다.

Re: [PATCH] ARM: decompressor: Fix mmu mapping for non-DRAM address space.

On Wed, May 9, 2012 at 5:53 PM, Russell King - ARM Linux <lin…@arm.linux.org.uk> wrote: On Wed, May 09, 2012 at 02:20:28PM +0530, Shilimkar, Santosh wrote: The only change done common code is clearing 'XN' bit for DRAM region in page table entries. The other change of setting the DACR register is done in ARMv7 specific code. Yes, XN is an ARMv6+ thing. Before ARMv5, it was implementation defined.

Some implementations used the bit to mean “allow writes to update the cache”. Other implementations labelled this bit as “should be zero” while others labelled it as “should be one”.

Good to know.

The upshot of this is, we know that having this bit as '1' means that all the CPUs we support today work. I would be very concerned to change this bit to zero as we really don't know how the pre-ARMv6 CPUs would react.

I agree.

The solution to this is pretty simple - if ARMv6+ needs a different base section mapping value, then we need to extract that from the code and pass in the base section mapping value.

I'll sort out a patch later today for this. Great.

그럼 대체 이게 뭘하는 과정이냐? Level1 page table을 만드는 중이다.

AP=11은 무슨 뜻인가? B.3.7.1에 보면 나오며, read/write 가능하다는 의미이다.

__setup_mmu를 수행하는 이유를 다시한번 간략하게 설명해 달라. 특정 256MB만 cacheable하고, 나머지는 non-cacheable하게 지정하는 것이다. 이렇게 하는 이유는, 다른 영역은 I/O device처럼 보이게 하려고 하는 것이다. 그리고 현 시점에서는, 가상메모리가 물리메모리에 1:1 맵핑된다고 보면 된다. 그래도 이해가 잘 안된다. 아래와 같이 정리할 수 있지 않나 싶다. 맞나요??? (C팀 신조어 E↗)

지금보면 Non-Cacheable과 Non-Bufferable을 같이 사용하는데, 묶어서 사용하지 따로 사용할 필요가 있는가? Non-Cacheable과 Non-Bufferable로 설정하면 strictly order로 처리한다. (기억 안나시는 분은 민홍 교수님 자료 보세요) Non-Bufferable만 설정하면 buffer가 쌓여있는 상황에서 나갈 때 IP 1번과, IP 2번 사이에서 뭐가 나갈지 모른다. setup_mmu 마지막에 보면 kernel 부팅을 flash에서 하는 경우가 있는데, 동작이 이해가 안간다. kernel 부팅을 flash memory에서 하는 경우가 있다. 이런 경우면 4GB 셋팅을 다 했지만, 현재 code가 flash영역에 있으니까 설정을 다시 하는 것이다. 만약 memory였다면, 의미없는 짓을 하는 것이다. 음.. 근데 flash 코드에서 이미 r6라는 값이 core architecture를 검사해서 설정한 것인데, 왜 다시 B를 on 시키는 것일까? r6는 page table section entry를 만들때 cache정책이 write back경우만 Bufferable flag가 들어가기 때문에(CB_BITS) 주석처럼 B set을 확실히 해주는 것으로 보입니다.

Q&A

  • Q1)
  • #git diff v3.9.6..8bb495e arch/arm/boot/compressed/head.S
  • 전 위의 명령을 이용하면 결과값이 나오지 않고 에러가 뜨는데, 모든 컴퓨터에서 이렇게 하면 확인할 수 있나요?
    • 제 노트북에서 확인하고 수정했는데 안되시는가보군요
    • 에러메시지와 현재 브랜치 목록 태그 목록, 최근 log를 보여주시면 확인하는데 도움이 될 것 같습니다.
    • 일단 위 명령의 의미는요
    • v3.9.6 태그로부터..8bb495e커밋까지의 변경사항 중에서 arch/.../head.S 파일의 변경내용만 보여달라는 명령입니다.
    • 이떻게 이 명령이 만들어졌냐면
    • 우리가 작업하던 버전에 v3.9.6이었으니까 먼저 태그가 있는지 확인해 봅니다.
    • git tag | grep v3.9.6
    • 태그가 있으면 v3.10의 커밋을 찾습니다. 이건 태그가 안붙어있어서 sha-1해시를 찾는겁니다.
    • git checkout master
    • git log --oneline --abbrev-commit
    • 566ce8e 레퍼런스 매뉴얼 추가
    • 04f07ed 2013/07/06
    • a8054cc 2013-06-22 ~ 2013-06-29
    • 8bb495e Linux 3.10
    • 둘 다 찾았으니까 위 명령으로 둘 사이의 차이를 이렇게 봅니다.
    • git diff v3.9.6..8bb495e arch/arm/boot/compressed/head.S