레이블이 linux kernel인 게시물을 표시합니다. 모든 게시물 표시
레이블이 linux kernel인 게시물을 표시합니다. 모든 게시물 표시

2011년 7월 27일 수요일

OMAP2 processor에서 kernel의 secondary bootup

리눅스 커널을 스터디를 통해서 분석한지가 벌써 4년전인것 같다.

그떄 당시는 2.6.15버젼인가가 최신이고 2.6.13이 안정판이라 arm rearview 기반으로

2.6.13 버젼을 분석했던 기억이 난다. 

분석 초기에 개인적으로는 smp 머신에서 초기화는 1개의 cpu에서 해주고 

나머지 cpu를 어떻게 startup 해주는지가 상당히 궁금했다. 

다음은  당시에 내가 썼던 글이다. 

===============================
kernel_init  커널 쓰레드에서 다른 CPU를 다 꺠워준다. 

호출 순서는 다음과 같다.

start_kernel() -> rest_init() -> kernel_init -> smp_prepare_cpus() -> poke_milo() ( SYS_FLAGSCLR 레지스터의 
하위 2비트를 클리어) -> (pen_release = -1, realview_secondary_startup() )

후에 rearview_secondary_startup 루틴이 pen 값이 release 될때까지 루프

kernel_init -> smp_init() -> cpu_up() -> _cpu_up() -> __cpu_up() -> boot_secondary() -> pen relase

후에 realview_secondary_startup() 루틴이 secondary_startup()으로 점프하면

secondary_startup() 함수에서 나머지 cpu를 up 해준다. 

=================================

omap2에서도 크게 달라지지 않았지만 달라진 부분이 있다면 boot_secondary() 에서 

omap_modify_auxcoreboot0(0x200, 0xfffffdff);로 두번째 core의 startup을 준비하는 부분과

를 부팅한다는 점과  정도이다. 

2011년 7월 16일 토요일

linux kernel의 cache clean과 cache flush

ARM System Developer's Guide에 보면 


cache clean과 cache flush에 대해서 자세히 설명되어 있다.


flush는 cache를 그냥 비워버리고 clean은 write buffer의 데이터를


메모리에 write한 후 cache를 지운다. 


커널의 코드를 살펴보면 다음과 같다. ( 2.6.13 버젼 기준 )


static inline void flush_pmd_entry(pmd_t *pmd)
{
        const unsigned int __tlb_flag = __cpu_tlb_flags;

        if (tlb_flag(TLB_DCLEAN))
                asm("mcr        p15, 0, %0, c7, c10, 1        @ flush_pmd"
                        : : "r" (pmd) : "cc");
        if (tlb_flag(TLB_WB))
                dsb();
}

static inline void clean_pmd_entry(pmd_t *pmd)
{
        const unsigned int __tlb_flag = __cpu_tlb_flags;

        if (tlb_flag(TLB_DCLEAN))
                asm("mcr        p15, 0, %0, c7, c10, 1        @ flush_pmd"
                        : : "r" (pmd) : "cc");
}

flush 의 경우에는 


if (tlb_flag(TLB_WB)) dsb(); 


코드가 있어서 write back  캐시정책을 사용하는 경우에는


장벽을 사용해서 write buffer까지 비워버린다.
 
따라서 flush의 경우에는 캐시에서 지우게 되는 라인이 메모리에 쓰여지지 않고

clean의 경우에는 지우는 라인의 데이터가  write buffer에 남아있으므로 


메모리에 쓰여지게 되는 결과가 나타나게 된다.


정리하면 다음과 같다.



Flush
- cache를 0으로 클리어
- cache line의 유효비트를 0으로 셋팅

Clear
- cache의 dirty cache line을 메모리로 쓴 후 dirty bit를 0으로 셋팅 

stubs_offset

entry-armv.S 파일에서는 
stubs_start
       ...
stubs_end
vectors_start
       ...
vectors_end

순서로 코드가 작성되어 있는데 이를 trap_init() 함수에서는
 
memcpy((void *)vectors, __vectors_start, __vectors_end - __vectors_start);
memcpy((void *)vectors + 0x200, __stubs_start, __stubs_end - __stubs_start);


로 복사한다. 

0xffff0000 에 vectors_start 부분부터 복사해놓고
0xffff0200 에 stubs_start 부분부터 복사하게 된다. 

따라서 
                               stubs_end
stubs_start <--x--> vector_start  라고하면 stubs_offset 값은 
                     
vectors_start<--0x200--> stubs_start <--x--> stubs_end (stubs_offset의 위치)


로 바뀌게 된다.

stubs_offset 값은  __vectors_start + 0x200 - __stubs_start  = 0x200 + x 이니깐


재배치한 후의 stubs_end와 같은 위치를 가리키게 된다.

따라서 상대주소로 점프하는 b 명령어가 정상적으로 작동한다.