본문 바로가기
WINCE 포팅 완료까지의 절차가 어떻게 되죠?

뭘 알아야 이해를 하지

부트로더 Eboot에서 Kernel까지 알아 보도록 하죠.
WINCE도 마찬가지인데, 개발 보드 BSP에 있는 소스를 수정하지 않고도 BSP에 있는 문서대로 따라만 하면 포팅을 하는데는 전혀 어렵지 않습니다. 다만, 실제 제품으로 만들 때는 소스 수정할 일이 있기 마련입니다.
C:\WINCE600\PLATFORM\ARM11\Src\Bootloader\Eboot 폴더를 보시면 다음과 같은 파일이 있답니다.

# 부트로더
개발자는 부트로더 포팅을 위해서는 아래의 순서대로 하시면 된답니다.


Interrupt 관련한 내용을 살펴보죠. Interrupt enalbe clear register라고 불리는 VIC0INTENCLEAR(VIC0), VIC1INTENCLEAR(VIC1) 두 개의 레지스터가 있고, 1의 값은 interrupt disable in VICINTENABLE register 의미랍니다. 그래서 모두 0x1의 값을 가진 0xFFFF FFFF 값을 넣게 되면 모든 Interrupt는 disable된답니다.

다음으로는 Watchdog timer를 disable 한답니다. Watchdog timer control register라고 불리는 WTCON 레지스터이며, [0]bit의 값이 0이라면 Disable the reset function of the watchdog timer의미를 가진답니다. 그래서 [0] bit값을 0으로 설정하면 된답니다.

다음으로는 PLL 설정이랍니다.
ARM1176JZF-S 프로세서는 APLL(ARM core), MPLL(main), EPLL(extra) 3개의 PLL이 있어요.
APLL은 ARM core를 동작시키기 위해서 설정하는 PLL이랍니다. MPLL은 AXI, AHB, and APB bus 동작을 위해서 사용된답니다. 그리고 EPLL은 일반적인 패리퍼럴을 동작하기 위한 클럭으로 사용되는데, 주로 UART, IIS, IIC 등 사용된답니다.

다음으로는 인터럽트랍니다. ARM11에서는 2가지 표준 인터럽트 컨트롤러와 벡터 인터럽트 컨트롤러(VIC, Vector Interrupt Controller) 방식이 있답니다. 표준 인터럽트는 외부 디바이스가 인터럽트 서비스 요청을 하면, 그 인터럽트 신호를 ARM 프로세서에게 신호를 보내면서 처리가 되고, 이 때 인터럽트 처리하는 주소가 고정 되어 있답니다. 벡터 인터럽트는 인터럽트마다 우선 순위를 주고, 외부 디바이스가 서비스 요청을 해서 인터럽트가 발생하면, 우선 순위와 각 인터럽트를 처리하는 주소(인터럽트 핸들러)에 대해 살펴보고, 현재 실행되는 인터럽트 주소(인터럽트 핸들러)보다 우선 순위가 높은 경우에만 ARM 프로세서에게 인터럽트 신호를 보내게 된답니다. 그리고 주변 장치가 인터럽트를 처리할 주소를 제공하기 때문에 서로다른 벡터 주소를 가진답니다.
S3C6410의 경우는 VIC 두 개가 있으며, 각각 32개씩 인터럽트 소스에 연결되어 있지요.
벡터 인터럽트 컨트롤러는 표준 인터럽트 컨트롤러에 대해 인터럽트 처리과정이 더욱 간소화된 구조라서 인터럽트 처리 속도를 높일 수가 있답니다.
이러한 벡터 인터럽트를 사용여부를 결정하기 위해 System_DisableVIC 코드가 실행되며, 여기서는 VIC를 Disable 하지요.

실제 System_DisableVIC 코드를 보면 어셈블리 명령어로 되어 있고, MRC와 MCR 명령어가 사용됩니다. 두 개의 명령어는 Co-processor 명령어 인데, S3C6410의 ARM1176 Core의 경우 VIC 사용여부는 Co-processor 레지스터인 CR(Control Register)에서 담당하고, 그 중에서 VE(Vector Enable)라는 필드를 제어하도록 되어 있답니다. VE값이 '0'이면, Fixed이고, '1'이면 VIC랍니다. 위의 코드가 실행되면, VE값은 Fixed라는 값을 가지게 된답니다.

이제 IRQ 인터럽트를 Enable해 보죠. ARM core에서 IRQ 관련은 CPSR 레지스터에서 관리를 한답니다.

그 중에서 [7]번째 비트가 IRQ Enable, Disable을 해 주고 있답니다. CPSR[7] 비트가 '0'이면 Enable이고, '1'이면 Disable랍니다.

다음으로 SDRAM을 초기화 해 보죠. 부트로더가 커널 바이너리를 SDRAM으로 복사하기 위해서 SDRAM이 읽고/쓰기 상태가 되어야 하니 초기화를 해야 하죠.

다음으로 MMU 관련한 부분을 설정한답니다. 부트로더가 커널 바이너리를 SDRAM으로 복사될 때 그냥 복사하는 것보다 캐시를 사용해서 복사를 되면 1.5배 빠르게 때문에 캐시 사용을 위해서 MMU 관련 설정을 한답니다. 그래서 부트로더는 물리주소가 아닌 가상 주소에서 동작을 하게 되어 있답니다.

마지막으로 main 함수로 점프를 하게 되죠.

이제 드디어 main 함수로 진입을 하게 됐네요. ^^;

BootloaderMain 함수 안에 OEMPlatformInit 함수가 있답니다. 이 함수는 UART, Ethernet, USB와 같은 장치들을 초기화해 주고 Bootloader 메뉴 출력 및 플래시 메모리 설정 관련한 부분이 들어 있답니다.
개발 보드와 제품 보드의 부품이 모두 동일하다면 BSP에 있는 소스 그대로 사용하면 되지만 그렇지 않다면 반드시 소스를 만들어 주셔야 해요. 부트로더의 역할중에 커널을 SDRAM으로 복사하는 일이 중요한데, 그러기 위해서는 우선 플래시 메모리에 있는 커널 이미지를 가지와야 하죠. 즉, 플래시 메모리를 읽고, 쓰고, 지우고를 자유롭게 할 수 있어야 한다는 뜻이죠.

아래의 경로를 보시면 플래시 메모리 관련한 내용이 있답니다.
c:\wince600\platform\arm11\src\common\nandflash\fmd\fmd.cpp

제일 먼저 CPU가 현재 개발 보드에 어떤 낸드가 있는지 확인하는 과정을 'NAND ID' 체크라고 하고, 'NAND ID' 정상적인 값이 나온다면 하드웨어적으로 CPU와 낸드 플래사 사이의 인터페이스 및 낸드 컨트롤러 설정하는 소스에는 문제가 없다는 뜻이랍니다. 'NAND ID' 값은 개발 보드에 붙여 있는 낸드 플래시 이름을 보고, 해당 이름을 인터넷으로 검색해서 데이타 시트를 찾아보면 알 수가 있답니다. 검색어를 Device code 라고 하시면 ID값이 나온답니다.

이제 Eboot 부트로더 메뉴가 나온답니다.
메뉴는 주로 Ethernet setup, Download, NAND Erase, BinFS format, Kernel 진입 등이 있답니다.
Ethernet setup은 Eboot.bin, Nk.bin 파일을 다운로더하기 위해서 호스트 피시와 개발 보드를 인터페이스 하기 위해 설정한답니다. Download는 Ethernet으로 setup이 끝나면 호스트 피시에서 개발 보드로 Download를 해 주는 것이고, BinFS format은 WINCE용 바이너리인 *.bin 파일 포멧이 지원 될 수 있도록 해 준답니다. 즉, 플래시 메모리 영역을 *.bin 파일 포멧으로 읽을 수 있도록 시작주소, 길이, 체크섬 섹션으로 나누고 섹션 헤더를 포함하도록 해 준답니다. Download, NAND Erase 내용이 바로 낸드 플래시 메모리에 대해 포팅 작업을 해 주셔야 하죠. 부트로더 단계에서는 크게 NAND Flash, Ethernet, USB, UART 관련한 포팅 작업이 가장 많답니다.
이제 부트로더 관련해서 포팅이 모두 끝났으면, OEMLaunch 함수에서 커널쪽으로 진입하게 된답니다. 이 과정에서는 낸드 플래시에 있는 커널 이미지를 SDRAM으로 복사하는 단계라고 보시면 됩니다.

# 커널
커널이 포함되어 있는 NK.BIN에는 OEM Layer인 BSP 관련된 것과 OS의 핵심인 커널, 디바이스 드라이버, 어플리케이션 서비스, 응용 프로그램 등 다양한 컴포넌트들이 있답니다.

부트로더에서 커널로 진입하면서 MMU을 인에이블을 하면 가상 주소인 4GB 영역이 만들어지는데, 커널 영역(Kernel space)와 유저 영역(User space)로 나누어진답니다.


커널 영역은 개발자들이 소스를 수정하거나 새로 만들어야 되는 부분은 거의 없다고 보시면 됩니다. 유저 영역에 올라가는 user DLLs 이나 어플리케이션만 개발을 하면 되죠. 그래서 대부분의 자료를 보시면 유저 영역에 올라가는 프로그램 방법에 대한 자료들이 많지요. 그런데 커널 부분이 너무 궁금하지 않나요? 그냥 지나치면 섭섭할 수 있으니 조금만 분석해 보죠. 커널 영역에서 실행되는 프로세스와 DLLs을 살펴볼게요.

1. NK.EXE(OAL.EXE): 커널진입 시 가장 먼저 실행되는 프로세스랍니다. OEM layer에 해당 되며 커널이 Kernel.dll을 실행시킨 답니다.
2. KERNEL.DLL: 핵심 OS Services 담당하고, 프로세스, 쓰레드, 메모리 매니지먼트와 같은 로-레벨(Low-level) 일들을 처리해 준답니다. 마이크로 커널로 구성되어 있어 여러 시스템 프로세스를 사용할 수 있으며, 커널의 과부하를 최소한으로 하여 멀티미디어나 인터넷과 같은 많은 서비스를 제공해 준답니다. 예를 들어, 하나의 어플리케이션이 실행 되어 특정 파일을 접근할 때 커널은 파일 시스템 관리자(Filesys.dll)와 저장 장치를 관리하는 디바이스 드라이버 관리자(Devmgr.dll)를 통해서 저장장치의 파일을 접근하게 해 준답니다.
3. FILESYS.DLL: 초기화 순서, 레지스트리, CDDB 데이타베이스 등을 관리하죠. SDRAM에 오브젝트 스토리지라는 영역으로 초기화 하면서 가장 중요한 '시스템 디폴트 레지스트리'를 설치하죠. 레지스터리에 등록되어 있는 내용을 참조해서 다음에 실행할 프로세스을 호출한답니다.
4. FSDMGR.DLL: 파일시스템(File system), 필터(filter), 저장 매체 관리(storage manager)해요.
5. DEVICE.DLL: GWES.DLL에서 관리하지 않는 나머지 모든 드바이스 드라이버들을 관리해요. DEVICE에서 로드되는 드라이버들을 스트림 드라이버(Stream driver)라고 부른답니다. 스트림 드라이버는 어플리케이션에서 File-system 의 CreateFile 함수 API를 통해서 드라이버를 오픈하게 됩니다. OS부팅 시 또는 부팅 이후 동적으로 로드가 됩니다.
6. DEVMGR.DLL: 디바이스 드라이버 서비스 한답니다.
7. NDIS: 네트워킹 관련 서비스
8. GWES.DLL: 그래픽, UI library, 윈도우, 메뉴, 그래픽 윈도우 관리와 이벤트 관리 등을 합니다. 즉, 사용자 입력과 화면 출력을 담당하는 컴포넌트인데 키보드, 마우스, 디스플레이 드라이버, 터치 드라이버 등이 있답니다. GEWS에서 로드되는 드라이버를 네이티브 드라이버(Native driver)라고 부른답니다.

부팅 과정은 다음과 같아요.
NK.EXE -> KERNEL.DLL -> K.COREDLL.DLL -> FILESYS.DLL -> FSDMGR.DLL -> DEVICE.DLL -> DEVMGR.DLL -> NDIS -> GWES.DLL

NK.EXE 분석해 보아요.
C:\WINCE600\PLATFORM\ARM11\Src\OAL\OALLIB\startup.s 파일에서부터 시작 됩니다.
\NK.EXE startup.s 커널 부팅 초기화 관련

부트로더 이후 커널로 진입을 하면 NK.EXE 프로세스가 실행 되는데, 가장 먼저 실행되는 소스 코드는 startup.s랍니다. 여기에는 개발 보드 설정관련 및 KernelStart 함수를 호출한답니다.

이제 KernelStart 함수로 가게 되는데, 이 쪽은 library로 되어 있어 소스를 볼 수가 없어요. 그래서 Disassembler code를 보시면 KernelStart 함수가 있고, 여기서는 다시 ARMInit 함수 호출을 하는 것을 볼 수가 있답니다.

ARMInit 함수에서는 Kernel.dll 로딩해서 실행하기 위한 준비를 하게 되죠. (C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\LDR\ARM\arminit.c)

FindKernelEntry 함수에서는 Kernel.dll 찾은 다음 Kernel.dll의 시작 함수로 점프 한답니다. (C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\ldr\ldrcmn.c)

KERNEL.DLL 에 대해 알아 보아요.
대부분 C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL 경로에 있답니다.
Kernel.dll의 시작 함수는 NKStartup 이랍니다.
(C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\ARM\mdarm.c)

OEMInit 함수는 NK.EXE의 OEMInit(A) 함수로 점프를 한답니다.
(C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\oemstub\oemstub.c)

NK.EXE의 OEMInit 함수로 와서 개발 보드 관련 초기화를 한답니다.
(c:\wince600\platform\arm11\src\oal\oallib\init.c)

이제 다시 Kernel.dll의 NKStartup 함수에서 KernelStart(B) 함수를 실행하죠. KernelStart 함수도 소스가 없고 Library로 되어 있답니다. 이제 이곳에서는 KernelInit 함수로 점프 한답니다.

KernelInit 함수는 스케줄러에 의해 첫 번째 쓰레드를 실행하기 전인 커널 초기화하는 과정을 한답니다.
(C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\nkinit.c)

PROCInit 함수 실행이 끝나고 나면 NK.EXE 프로세스가 생성된답니다.

THRDInit 함수 실행이끝나고 나면 NK.EXE 쓰레드가 생성된답니다.

THRDInit 함수에서 생성한 쓰레드의 심볼을 참고하여 Kernel.dll의 SystemStartupFunc 함수로 진입한답니다.
(C:\WINCE600\PRIVATE\WINCEOS\COREOS\NK\KERNEL\schedule.c)

PagePoolInit(A) 함수를 실행을 하고 나면 몇 개의 쓰레드가 생성됩니다.

그리고 B, C 구간의 함수를 실행하면, PowerHandlerGuardThrd 이름을 가진 두 개의 쓰레드가 생성됩니다.

D 구간의 함수를 실행하면, RunApps 이름을 가진 쓰레드가 생성됩니다.

기본 쓰레드가 생성된 후에는 k.coredll.dll의 ThreadBaseFunc 함수가 시작된답니다. (C:\WINCE600\PRIVATE\WINCEOS\COREOS\core\dll\loader.cpp)

A 구간의 함수는 여러 번 실행이 된답니다.
처음 실행 됐을 때는 PowerHandlerGuardThrd 이름을 가진 쓰레드를 실행하고, 두 번째로 실행 됐을 때는 RunApps 이름을 가진 쓰레드가 실행이 된답니다. 세 번째 이후 부터는 WINCE 관련 모든 DLLs이 로딩 된답니다. DLLs은 쓰레드를 먼저 생성한 후 DLL들이 메모리로 로딩 되기 때문에 이 시점 이후 생성되는 쓰레드는 대부분 DLLs 실행하기 위해 만들어 지는 것이라고 생각하시면 됩니다.
메모리에 로드 되는 순서를 간단히 나열하면 다음과 같아요.

커널 영역에서 유저 영역으로 넘어가면서 Udevice.exe와 ServicesD.exe 프로세스가 실행 한답니다.
Udevice.exe는 유저 영역의 디바이스 드라이버를 지원하고, 유저 모드로 드라이버를 로딩하지요. 주로, video.dll, i2c.dll, wavedev.dll 같은 드라이버랍니다. ServicesD.exe는 여러 서비스들을 관리한답니다. 주로, 쓰레드 단위로 실행을 한답니다.

부팅이 완료가 됐을 때, NK.EXE 프로세스에서 만든 쓰레드의 총 개수가 76개이고, udevice.exe 프로세스는 5개, 쓰레드는 11개랍니다. explorer.exe 프로세스는 4개의 쓰레드, 마지막으로 servicesd.exe 프로세스는 7개의 쓰레드를 만든답니다.

Startup.s - "301” Co-processor명령어 - "201” 표준 인터럽트 - "206” 캐시메모리 -"309"


Linked at 친절한 임베디드 시스템 개발자.. at 2011/04/03 17:15

... WINCE 포팅 완료까지의 절차가 어떻게 되죠? ... more

Commented by ruring at 2011/04/08 15:17
-_-)a 책사야하는데욤............................
-_- 일등책 주세요 빼놓으셨죵?
계좌번호불러줘욤 주실땐 사인해서 주시공
1빠 인증 사인 =-=ㅋ
Commented by soto at 2011/04/11 05:06
하하...
반갑습니다.
사인된 책은 아직 없으니 걱정마세염~~!!
※ 이 포스트는 더 이상 덧글을 남길 수 없습니다.
친절한 임베디드 시스템 개발자 되기 강좌 글 전체 리스트 (링크) -



댓글





친절한 임베디드 개발자 되기 강좌 글 전체 리스트 (링크) -