2014년 2월 26일 수요일

[Linux Kernel] 43주차(2014.02.22) 후기

* 43주차
10차 ARM 리눅스 커널 스터디 43주차(2014.02.22) 후기입니다. 

# 일시 : 2014.02.22 (43주차)
# 장소 : 토즈 타워점
# 참여인원 : 5명
# 스터디 진도 : start_kernel()-> setup_per_cpu_areas() -> pcpu_embed_first_chunk();

# 스터디 내용
 mm_init_owner(&init_mm, &init_task); 
  // null function;
 mm_init_cpumask(&init_mm); 
  // null function 
 setup_command_line(command_line);
  // saved_command_line 및 static_command_line 할당
 setup_nr_cpu_ids();
  // nr_cpu_ids: 4 = (3 + 1)
 setup_per_cpu_areas();
   rc = pcpu_embed_first_chunk(PERCPU_MODULE_RESERVE,PERCPU_DYNAMIC_RESERVE, PAGE_SIZE, NULL,pcpu_dfl_fc_alloc, pcpu_dfl_fc_free); 
    // 분석 중

# &init_mm, &init_task 는 어디서 정의했을까?
extern struct task_struct init_task;
extern struct mm_struct init_mm;
으로 컴파일에서 자료구조(init_task, init_mm)을 초기화했었다. 

# mm_init_owner(&init_mm, &init_task); 
// NULL 함수이다. 

# mm_init_cpumask(&init_mm);
// NULL 함수이다. 

# setup_command_line(command_line);
command_line 은 어디서 왔을까?
exynos5420-smdk.dts 에 보면 chosen에 bootargs가 있다. 
<code>
        chosen {                                                                                                                                                                                          
                bootargs = "console=ttySAC2,115200 init=/linuxrc";                                                                                                                                        
        }; 
</code>

# static void __init setup_command_line(char *command_line)                                                                                                  <code> 
{                                                                                                                                                                                       
        saved_command_line = alloc_bootmem(strlen (boot_command_line)+1);                                                                                    static_command_line = alloc_bootmem(strlen (command_line)+1);                                                                                     
        strcpy (saved_command_line, boot_command_line);                                                                                                         
        strcpy (static_command_line, command_line);                                                                                                                 
</code>
saved_command_line은 고정할 것이고, static_command_line은 수정될 수도 있다 

# setup_nr_cpu_ids(void)
void __init setup_nr_cpu_ids(void)
{
   nr_cpu_ids = find_last_bit(cpumask_bits(cpu_possible_mask), NR_CPUS) +1;
}

nr_cpu_ids : cpu_possible_mask[1]에서 지난 시간에 bit를 마킹하고 왔기
때문에 3이 되고 여기에 +1을 하면 nr_cpu_ids는 4가 된다. 
만약 NR_CPU가 32보다 크다면 cpu_possible_mask[2] 이런식으로 될 수 있다. 

# find_last_bit(cpumask_bits(cpu_possible_mask), NR_CPUS) +1
이 함수는 size만큼 0xFFFF를 shift한 후, &로 마스크를 씌워서 값을 추출한다.
즉 이 경우 cpu_possible_mask[1]의 bits값이 추출된다. 

# setup_per_cpu_area();
 이 함수는 CPU (core)마다 사용할 메모리를 할당하는 과정이다. 멀티 코어 
시스템에서는 여러개의 core가 공동으로 사용될 메모리 영역과 각 core를 위한 
메모리 공간이 필요하다. 각 core가 사용하는 데이터를 다른 core가 접근하지 
못하도록 분리하여 lock과 같은 동기화를 하지 않아도 안전하고 빠르게 데이터를
접근하기 위한 방법이다.  
setup_per_cpu_area()는 각 core가 사용할 메모리를.data.percpu 섹션으로 
컴파일시 하나만 만들고, 커널의 초기화 과정에서 만들어 놓은 섹션을 core수 
만큼 메모리에 복제하는 과정이다. 

# pcpu_embed_first_chunk()
ai 구조체 계산하기
ai는 반드시 한개는 있어야만 하고, nr_group 크기만큼 ptr 이 이동한다.
우리는 nr_group이 1이므로 ptr은 44가 되지만, 
만약 nr_group이 3이라면 prt은 68이 된다. 
ptr 이후에 cpu_maps[0] ... cpu_maps[n]이 위치한다. 
  
# git log
   1460dc7..38f9803  master     -> origin/master
Updating 1460dc7..38f9803
Fast-forward
 Reference/exynos5420-smdk5420_dtb.txt | 804 ++++++++++++++++++++++++++++++++++
 arch/arm/include/asm/bitops.h         |   7 +-
 arch/arm/include/asm/dma.h            |   1 +
 arch/arm/include/asm/memory.h         |   9 +
 arch/arm/kernel/devtree.c             |   2 +-
 include/linux/cpumask.h               |   1 +
 include/linux/err.h                   |   3 +
 include/linux/kernel.h                |   5 +
 include/linux/kmemleak.h              |   1 +
 include/linux/mm_types.h              |   3 +-
 include/linux/of_fdt.h                |   2 +-
 include/linux/percpu.h                |  14 +-
 include/linux/pfn.h                   |   2 +
 include/linux/sched.h                 |   3 +-
 init/main.c                           |  21 +-
 kernel/smp.c                          |   3 +
 lib/find_last_bit.c                   |   7 +
 mm/percpu.c                           | 152 ++++++-
 18 files changed, 1029 insertions(+), 11 deletions(-)
 create mode 100644 Reference/exynos5420-smdk5420_dtb.txt

# samsung exynos5 smdk 
samsung_exynos_5_gaia_smdk.jpg

2014년 2월 19일 수요일

[Linux Kernel] 42주차(2014.02.15) 후기

10차 ARM-C 42주차 스터디 후기입니다. 

# 일시 : 2014.02.15 (42주차)
# 장소 : 토즈 타워점
# 스터디 진도 : start_kernel() -> setup_arch() 종료

# 지난 9월 14일에 시작한 setup_arch()가 2월 15일스터디로 만 5개월만에 분석을 끝냈습니다. 
# setup_arch의 주요 함수 분석 요약:
setup_processor(); 
 // 각 프로세서에 의존적인 초기화 함수 구조체를 할당하고 현재 cpu에 대한 모드를 스택에 설정함
mdesc = setup_machine_fdt(__atags_pointer);
 // dtb에서 memory bank설정, cmd arg 설정, arch type 설정, mdesc 검색.
parse_early_param(); 
 // command arg에서 각 요소들을 파싱하여 early init section으로 설정된 디바이스 초기화.
sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
 // page frame number 기준으로 정렬
sanity_check_meminfo();
 // memory bank에서 bank하나가  valloc limit 을 넘으면 2개로 쪼갬.bank[0]:low bank[1]:high
arm_memblock_init(&meminfo, mdesc);
 // meminfo를 참조하여 메모리 블록 구조체를 초기화 
paging_init(mdesc);
 // mmu용 page table (pgd, pte)을 생성
 // zone 영역 3개로 나누고 각 zone에 해당하는 page를 할당함
unflatten_device_tree();
 // device tree를 flat tree에서 실제 tree로 생성
 // of_allnodes, of_chosen, of_aliases, aliases_lookup 만들어 줌
arm_dt_init_cpu_maps();
 // devtree에 cpu node의 reg 값을 읽어서 cpu_possible_bits, __cpu_logical_map의 값을 업데이트 함 
smp_set_ops(mdesc->smp);
 // smp_ops: exynos_smp_ops 을 할당 
smp_init_cpus();
smp_build_mpidr_hash();
 // mpidr_hash 의 cache에 있는 값을 실제 메모리에 반영 

# 스터디 log 
Updating 24ab35a..1460dc7
Fast-forward
 arch/arm/include/asm/bitops.h                 | 18 +++++++
 arch/arm/include/asm/cacheflush.h             | 17 ++++++-
 arch/arm/include/asm/cputype.h                | 21 +++++++++
 arch/arm/include/asm/mach/arch.h              |  3 +-
 arch/arm/include/asm/outercache.h             |  1 +
 arch/arm/include/asm/prom.h                   |  3 +-
 arch/arm/include/asm/psci.h                   |  4 +-
 arch/arm/include/asm/smp.h                    |  1 +
 arch/arm/include/asm/smp_plat.h               |  6 +++
 arch/arm/kernel/devtree.c                     | 28 +++++++++++
 arch/arm/kernel/setup.c                       | 83 +++++++++++++++++++++++++++++----
 arch/arm/kernel/smp.c                         |  7 +++
 arch/arm/lib/findbit.S                        |  2 +
 arch/arm/mach-exynos/mach-exynos5-dt.c        |  2 +
 arch/arm/mach-exynos/platsmp.c                |  7 +++
 arch/arm/plat-samsung/include/plat/map-base.h |  2 +
 arch/arm/plat-samsung/include/plat/map-s5p.h  |  6 +++
 drivers/of/base.c                             | 48 +++++++++++++++++--
 drivers/of/fdt.c                              |  2 +
 drivers/tty/vt/vt.c                           |  1 +
 drivers/video/console/dummycon.c              |  2 +
 include/asm-generic/bitops/const_hweight.h    |  3 ++
 include/linux/bitmap.h                        | 12 +++++
 include/linux/bitops.h                        |  5 ++
 include/linux/compiler.h                      |  1 +
 include/linux/console.h                       |  1 +
 include/linux/cpumask.h                       | 25 +++++++++-
 include/linux/of.h                            | 16 ++++++-
 include/linux/threads.h                       |  3 ++
 include/linux/types.h                         |  2 +
 init/main.c                                   |  3 ++
 kernel/cpu.c                                  |  9 +++-
 kernel/smp.c                                  |  3 ++
 scripts/kconfig/list.h                        |  3 ++
 34 files changed, 329 insertions(+), 21 deletions(-)

# 다음 스터디(43주차)는 mm_init_owner(&init_mm, &init_task);부터 시작하기로 하였습니다. 

2014년 2월 12일 수요일

[Linux Kernel] 41주차 (2014.02.08) 후기

오래간만에 C팀 후기를 올립니다. 내용이 전과 같을 수는 없겠지만, 후기를 적습니다. 

42주차 스터디 : setup_arch() -> unflatten_device_tree(); 
장소 : 토즈 타워점
42주차 스터디는 네이버의 개발자 후원을 받아서 진행되었습니다.


주요 토론 내용 :
# 디바이스 트리를 읽어서 트리형 자료구조를 만드는 과정입니다.
두번 실행되며 삼중포인터 해석을 많은 시간을 들여서 분석했습니다.

# root node에서 왜 fpsize =1, allocl = 2로 설정하는가?
 이것은 root node일때만 fpsize =1, allocl = 2, *pathp = ‘\0’ 으로 구분해서 선언을 한다.
choosen일 경우는 fpsize는 choosen의 문자열 크기인 7만큼 증가해서 fpsize = 1 + 7 = 8
allocl = 8로 되어 각 노드별로 문자열 크기만큼 증가해 가면서 alloc을 한다.

# dtb에서 @가 나오는 예시
@뒤에는 어드레스 값이 나오게 된다.

<code>             
 cpu0: cpu@0 {
device_type = "cpu"; 
  compatible = "arm,cortex-a15"; 
  reg = <0x0>; 
clock-frequency = <1800000000>; 
               }; 
cpu1: cpu@ 1 {
device_type = "cpu"; 
compatible = "arm,cortex-a15"; 
reg = < 0x1>; 
clock-frequency = <1800000000>; 
               };
</code>

# 그럼 언제 루프를 빠져 나가게 될까?
OF_DT_END_N 0x02 와
OF_DT_END 0x09 가 나오면 끝나게 된다.

# size = unflatten_dt_node(blob, 0, &start, NULL, NULL, 0);
노드마다 flat DTB 를 tree 자료 구조로 만들기 위한 size를 계산하려는 것이다.
이것은 DTB에 존재하는 모든 node와 property에 대해서 각각
struct node + node 이름 문자열 길이, struct property + property 이름 문자열 길이에
필요한 크기가 size가 된다.
# ((__be32 *)mem)[size / 4] = cpu_to_be32(0xdeadbeef);
mem 공간의 마지막 4바이트 위치(맨 마지막)에 BigEndian으로  deadbeef를 설정한다.
deadbeef는  STACK_MAGIC이다.


#  문제의 3중 포인터 시간
unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0); 
이곳은 두번 반복하게 되는데 우리는 두번째 패쓰는 [Second.root] 로 주석을 표기한다.

# *allnextp = NULL;
allnextp는 어떤 노드에서도 할당하지 않았고. 따라서 추정컨데
의미로 보면 모든 node가 allnextp를 가리켜야 할듯 싶은데,
마지막 np->allnextp에 null을 넣는다.
근데 이게 이상해서 다들 생각보니.

처음은 *** allnextpp → ** allnextp → *of_allnodes
다음은 *** allnextpp → ** allnextp 에서 여기서 np->allnext를 가리키게 되고
그다음은 *** allnextpp -> **allnextp 에서 np-allnext -> allnext 를 가리키게 된다.

그림 (사진) 참조

0208_1.jpg
0208-2.jpg

0208-03.jpg