본격적인 개발에 앞서 환경구축하는 방법을 설명한다. 차후에 설명할 개발서버에 접속하기 위해서는 계정이 필요하다. 이때는 ' DD규격그룹 이승진 연구원(oora@lge.com)' 에게 GP 계정을 요청한다.
개발 환경의 이해
현재 회사에서 사용하는 방법은 개발 서버에 접속해서 컴파일하는 식이다.
내 생각에 아마도 'svn + samba + win active directory' 의 조합인 듯 싶다. 그림으로 나타내면 다음과 같다.
다시 말해 윈도우 서버에 접속해서 특정 프로그램을 실행하여 소스코드가 있는 리눅스 개발 서버에 접속하게 된다.
이 때, 윈도우 서버를 거치지 않고는 바로 개발 서버에 접속되지 않는다.
서버 접속하기
윈도우 서버
일단 윈도우 서버에 접속해야 한다. 웹 브라우저에서 'swfarm.lge.com' 로 접속한다.
로그인을 해야 하는 데, ID 는 EP 계정을 적고, 비밀번호는 현재 사용하는 클라이언트(노트북)의 비밀번호를 적는다.
왼쪽에 사용할 수 있는 프로그램의 목록들이 나오는 데, 이를 사용하기 위해 먼저 'ICA Client for Windows' 를 설치해야 한다.
설치 후에는 아이콘을 클릭하여 프로그램을 사용할 수 있다.
리눅스 서버
윈도우 서버에서 'putty' 를 실행하여 '156.147.69.213' 에 접속한다(※ 이후 서버주소가 '156.147.69.237' 로 바뀌었다).
'156.147.69.237' 에 접속한다.
ID 는 EP 계정을 적고, 비밀번호는 1234 를 입력한다. 기본 비밀번호이기 때문에 적당한 것으로 바꾼다. 이후 접속한 후에 삼바 패스워드를 같은 비밀번호로 변경한다.
다음과 같이 변경한다.
$smbpasswd
개발서버의 비밀번호와 삼바의 비밀번호를 일치시키는 이유
일치시키지 않으면 윈도우 서버를 이용해서 프로그램을 실행시킬 때, 프로그램에 설정 해놓은 환경 설정이 사라져 버린다.
매번 실행시마다 환경 설정을 해주어야 하는 번거로움이 발생한다.
컴파일 하기
GP1
소스코드 가져오기
$cd work $svn co http://156.147.69.210/gp/trunk ./
work 디렉토리 아래에 소스코드를 가져오게 된다. 컴파일을 하기 위해서는 환경설정 파일(bcm3549linuxmips.env, saturnlinuxmips.env)을 적용시켜야 한다. 각각 모델 별로 다르기 때문에 컴파일 하려는 소스코드에 맞게 적용한다.
$source bcm3549linuxmips.env
부트 코드
$cd work/os/bcm3549_linux/boot $make
커널 코드
$cd work/src/apps/prj/atsc_bcm3549 $make
GP2
소스코드 가져오기
$cd work/gp2 $svn co http://156.147.69.210/gp2/trunk ./ $source saturnlinuxmips.env
부트 코드
$cd work/gp2/os/saturn6_linux/boot/boot_2nd $./mk.sh
커널 코드
$cd work/gp2/os/saturn6_linux/kernel/linux-2.6.26-saturn6 $make
애플리케이션 코드
$cd work/gp2/src/apps/prj/dvb_saturn6/ $make CFG=GP2_DVB_EU.cfg // 컴파일 $make epk GP2_DVB_EU.cfg // epk 생성
커밋 하기
사용자가 commit 을 할 때는 특정한 시점에 한 사람만에게만 전체 코드에 대해서 commit 할 수 있는 권한이 부여된다. 다시 말해 동시에 두명 이상의 사용자가 commit 할 수 없다는 뜻이다.
이것은 전체 코드에 대해 lock 을 걸기 때문에 가능하다. 만일 여러사람이 commit 을 하려고 시도한다면, 순차적으로 Queue 에 대기되고 commit 권한을 얻을 때까지 기다려야 한다.
commit 를 수행하기 전에 간단한 명령어들에 대해서 설명하겠다. 현재 개발환경에서는 alias 를 사용하여 간단하게 명령을 내릴 수 있도록 하고 있다.
명령어 | 설명 |
---|---|
lock | 자신이 수정한 코드를 제외한 나머지 모든 코드를 lock 시킨다 |
unlock | 모든 코드를 unlock 시킨다. 주로 commit 후에 다른 사람들을 위해 unlock 명령어를 사용한다 |
ci | commit 한다 |
pq | 현재 lock 을 위해 대기하는 큐의 상태를 출력한다 |
commit 하는 순서는 크게 'lock → ci → unlock' 로 구성된다. lock 명령어를 수행하면, 서버에 저장된 코드와 비교하여 최신파일로 업데이트한다(svn update).
lock 를 한 이후, 소스코드 말고 src/app_history.txt 파일을 수정해야 한다. app_history.txt 파일은 일종의 commit 로그파일이라고 볼 수 있는데, commit 을 할 때마다 새로운 리비전 번호와 수정된 사항을 간략하게 추가하여야 한다. 작성방법은 아래와 같다. 구체적인 작성방법은 app_history.txt 파일을 참고하기 바란다.
... +------------------------------------------------------------------------------ 0.1.45.31 : balupzillot reviewed by leehc 2009/02/26 15:00 1. [DVB][EU][모델명 표기] 모델명 표기시 bug 수정. [원인] 모델명 12th 공백을 포함하여, length를 고려하지 못함. [확인방법] 조정 장비로 모델명을 writing하여, instart 메뉴 및 diagnotics에 정확한 모델명이 표기되는 지 확인. 47인치 미만은 나와야 함. [확인모델] 구주향 전 모델 [예상 Artiface] 없음. 생기 조정반에서 최종 확인함. ...
이제 수정한 코드를 commit 해보자! 앞에서 수정한 app_history.txt 과 수정한 소스 파일이 commit 될 것이다. commit 시에 작성하는 메세지는 앞에 app_history.txt 에 작성했던 것을 그대로 적는다.
정상적으로 commit 되었다면, unlock 을 실행하여 다른 사람이 코드를 commit 할 수 있도록 한다.
$pq ================================================================================ Lock Owner ================================================================================ $lock QUEUE IN [wjkim] 'app_history.txt' 는 'wjkim' 이/가 잠궜습니다. ================================================================================ Lock Owner wjkim ================================================================================ Locked by ME !!! $pq ================================================================================ Lock Owner wjkim ================================================================================ $ci $unlock Unlock [/vol/users/wjkim/work/src/app_history.txt] 'app_history.txt' 는 잠금이 해제 되었습니다. ================================================================================ Lock Owner ================================================================================
TortoiseSVN 사용시
위와 같이 콘솔에서도 사용할 수 있지만, TortoiseSVN 을 지원하기 때문에 간단히 gui 로도 commit 가 가능하다.
최종 방법
여러가지 이유로 인해 커밋하는 방법이 변경되었다. 가장 큰 차이점은 락(lock)이 없어졌다는 것이다. src/mw/ipm/test.c 라는 파일을 수정했다고 하자.
$cd src/mw/ipm/ $vi test.c # 파일 수정 $svnhelper template > log.txt $vi log.txt
아래와 같이 작성한다.
1. [일반변경][공통][IPM] 테스트.
아래와 같이 실행한다.
$svn ci -F log.txt
좀 더 자세한 방법은 commit.ppt 를 참고하기 바란다.
변경 사항
log.txt 의 포맷이 변경되었다. 아래와 같이 작성한다.
1. [Feature][CO][KERNEL] WI-FI Dongle 대응 커널 옵션 적용 (config-normal/config-flash)
기존의 방법과 비교해서 달라진 점은 '[ ]' 부분을 영어로 써야 한다는 것이다. 그렇지 않으면, Log Format 이 잘못되었다는 에러와 함께 커밋이 되지 않는다.
커널 커밋 하기
커널의 경우, 기존의 소스코드 커밋과는 조금 다르다. 커널의 코드 또는 설정파일(.config) 이 수정되었을 경우에는 .tgz 으로 압축하여 커밋을 해야 한다.
$cd /vol/users/wjkim/work/gp2/os/saturn6_linux/kernel/linux-2.6.26-saturn6 ### 수정 ### $cd .. $tar czf linux-2.6.26-saturn6.tgz linux-2.6.26-saturn6 $svnhelper template > log.txt $vi log.txt ## 수정 $svn ci -F log.txt
기타
개발 서버로 파일 업로드 하기
일반적으로 개발서버로는 파일을 업로드 하거나 다운로드 할 수 없다. 그래서 VMware 상에서 작성한 프로그램을 개발서버로 옮기려면 코드를 복사하는 방법 밖에는 딱히 없다.
이러한 번거로움을 피하기 위해서 파일을 간편하게 업로드 할 수 있는 프로그램이 있다. 다운로드 역시 가능하지만, 이 때에는 부서장의 결제를 받아야 한다. 여기서는 업로드 하는 방법만 설명하겠다.
실행파일(ProdUp.exe)을 실행하면, 프로그램 창이 뜬다. 아래와 같이 입력한다.
Path From | 업로드 할 파일 경로 |
Target Server | 업로드 할 개발서버(swfarm-linux) |
Target Home | 업로드 할 경로(/vol/users) |
Target Path | 업로드 할 개발 서버의 세부 경로 |
만일 fm 디렉토리 아래에 있는 test.c 파일을 서버에 올린다고 하자! 서버의 경우 일반적으로 /vol/users/ 아래 자기 계정 디렉토리 아래에 업로드 한다.
- 먼저 'search' 를 눌러 test.c 파일의 경로를 선택한다.
- 'Target Path' 에 'wjkim/fm' 을 입력한다.
- 'Upload' 를 선택한다.
개발 서버에 접속해서 제대로 업로드가 되었는지 확인해보자!
컴파일 시 에러가 발생하는 경우
현재 가지고 있는 코드가 svn 저장소에 커밋되어 있는 코드보다 낮을 경우, 컴파일 시에 에러가 발생할 수 있다. 가장 흔한 에러다.
이때는 work 디렉토리에 아래로 이동해서 'svn update' 를 실행한 후, 컴파일 한다.
DQMS 사용하기
QE 부서에서 테스트를 하고 나면, 문제점을 DQMS 에 올린다. 모든 문제들은 각각의 담당자별로 할당이 되는데, 이를 수시로 체크하여 문제점을 해결해야 한다. 문제점을 확인하는 방법은 다음과 같다.
- LGEP 에서 'My System → DQMS' 를 검색하여 추가한다.
- 접속한 후에, 'PRODUCT → Product Test → Input → Issue Status Mgt' 순으로 선택한다.
- Register 항목에 '이름'을 적고, 'Search' 를 누르면, 등록된 문제들이 출력된다.
- 문제를 해결했다면, 이를 DQMS 에 반영해야 한다. 방법은 해결할 문제를 지정하고 'Register Improvement' 를 클릭한다.
- 'Cause Class, Issue Cause, Issue Improvement' 를 작성한다. 이후, 'Save' 를 누른다.
- 만일 문제점이 'Major' 라면, 반드시 문서를 첨부해야 한다. 첨부하지 않으려면, 'Multi Improvement Report' 를 선택하면 된다.
Aging Test 방법
특정 시나리오의 안정성을 테스트하기 위해서 가장 많이 하는 테스트가 바로 Aging Test 이다. 이를 하기위해서는 다음과 같이 실행한다.
아래와 같이 debug 메뉴를 실행한다.
... aa DASY Menu ae SDM Menu af MFS Menu b0 SWU Menu b2 Autotest Menu c1 ATVCC Menu c2 DTVCC Menu e0 UI Menu ... 1:ORG MAIN $ b2 // b2 선택한다. ***** Auto Debugging Tool Shell ***** 0x1 : Save IR Input Sequence 0x2 : Stop saving IR Inputs 0x3 : Set repeat-Time 0x4 : Run saved IR Inputs 0x5 : Stop Autotest 0xff : Exit Select List Function : 0x1 // 1 입력 후에 테스트 하기 원하는 시나리오대로 동작시킨다. ... Select List Function : 0x2 // 시나리오를 모두 동작시켰다면, 저장을 종료하기 위해 2 를 입력한다. ... Select List Function : 0x3 // 앞서 저장한 시나리오를 몇 번 반복할 지 횟수를 지정한다. Repeat Value : 1000 ... Select List Function : 0x4 // 저장한 시나리오를 시작한다. ... Select List Function : 0x5 // 시나리오를 중지한다. ...
이와 더불어 로그를 남기기 위해, TeraTerm 에 로그를 저장할 수 있도록 설정한다.
양산 코드 커밋하기
양산 시점이 되면, 커밋 과정이 복잡해진다. 일반 커밋 로그를 작성했다가는 포맷이 다르다는 에러를 만나게 될 것이다.
먼저 코드 리뷰라는 것이 필요한데, 자신이 커밋할 코드를 다른 사람에게 확인 받는 작업이다.
여기서는 ui_netmgr.c 라는 파일을 가지고 설명하겠다. ui_netmgr.c 파일을 수정하여 커밋한다고 하자.
- diff 파일을 생성해야 한다. 현재 서버에 커밋된 코드와 어떤 부분이 다른지에 대한 diff 파일을 생성한다. 생성 방법은 '해당 파일 클릭 → 마우스 오른쪽 버튼 → SVN → Create patch' 를 선택한다. 커밋할 파일들을 체크한다.
- diff 화면이 출력되는 데, 여기서 적당한 diff 파일을 입력한다. 여기서는 nm 이라고 하자.
- 'swfarm → SWFARM Integration → ReviewBoard → New Review Request' 선택한다. 'GP2, trunk/src/ui/apps/netmgr, nm 파일 경로' 를 적어준다. 이 때, Base Path 를 적어야 하는데, nm 이 있는 경로에 가서 'svn info' 을 입력한다. 여기서 URL 항목의 trunk 부터 끝까지 경로를 적어주면 된다, 그리고 'Summary, Description' 에 설명을 적는다. 'Publish → Submit' 를 누른다
- 'All review requests' 를 선택하면, 오른쪽 항목에 'Review ID' 가 있다. 번호를 커밋 로그에 적어주어야 한다.
이제 커밋 로그를 작성할 차례이다.
Reviewed by sungbeen.han (Review ID : 1936) 1. [BCM][CO][CO][NM] 이란향 모델 대응을 위한 WIFI Country Code 추가 [cause] 이란향 모델이 추가되면서, 해당 국가에 대한 WIFI 기능이 대응되지 않음 [improvement] 이란에 대한 WIFI Country Code 를 추가함 [test] Country Code 를 이란으로 설정하고, WIFI 를 테스트함
위와 같이 입력하고 커밋하면 된다.
Mantis 사용하기
svn 서버에 커밋되어 있는 모든 소스코드는 일정시간마다 정적분석 검사를 받는다. 이를 통해 코딩 표준에 어긋나거나 버그가 의심되는 루틴을 알 수 있게 된다.
사용하는 방법은 다음과 같다.
- swfarm 접속 후 'SWFARM Integration' 실행한다.
- 'Mantis(New)' 를 선택 후 'View Issues' 를 선택한다. 이때, Project 는 GP3(2010년 기준) 로 선택한다.
- Search 항목에 'mw/nm' 을 입력하고 'Apply Filter' 를 누른다. 이 때 문제의 종류대로 보고 싶다면, Search 항목 앞에 '+' 를 누르면 서브 메뉴가 뜬다.
- 중간 상단에 있는 'Category' 를 누르면 선택 메뉴가 뜬다. 여기서 보고 싶은 항목을 선택하면 된다. 또한 'Hide Status' 메뉴를 누르고, 'closed' 된 문제는 출력되지 않는다.
- ID 를 클릭하고 문제가 되는 코드를 수정한다. 이후, 'Change Status To' 를 'resolved' 로 선택한다.
- 이후 로딩되는 페이지에서 'Resolution' 을 'fixed' 로 수정하고, 'Resolve Issue' 를 누르면 된다.
커널 메세지 덤프하기
DTV 프로세스가 죽지 않았다면, 화면이나 시리얼 포트를 통해 실행 로그를 볼 수 있지만, 만일 DTV 프로세스가 죽어버렸다면 볼 수 있는 방법이 별로 없다.
이 별로 없는 방법을 설명할 텐데, 이 방법으로 볼 수 있는 것은 커널 메세지 뿐이다.
나의 경우, 수명실에서 특정 세트 한대가 화면이 정지되면서 죽어버리는 문제를 검토하기위해 이 방법을 사용했다. 순서는 다음과 같다.
1. 먼저 동일한 리비전의 죽지 않은 세트에서 Shell 모드 진입 후 아래와 같이 입력한다.
$ cat /proc/kallsyms | grep __log_buf 80491f74 b __log_buf
2. 이후 죽은 세트에 BBS 를 연결하고, 위의 주소(0x80491f74)로 메모리 접근을 한다.
3. 메모리 값을 드래그하여 복사한다. 이를 메모장에 복사한다.
양산코드 커밋하기(GP3)
커밋 메세지 형식은 다음과 같다.
" [DEV]Review ID(3302) [BCM][CO][CO][NETWORK] [BASIC]WIFI [Feature]WIFI Direct 개발을 위한 컴파일 옵션 추가 [Cause]WIFI 기능 구현 [Improvement]컴파일 옵션 추가 [Test Condition]Build 후 동작 확인 [Test Result]정상 동작 확인함 [Always]O [Daily Test]N "
개발 PC 설정기
리스한 데탑에 우분투와 페도라를 설치하려고 했다. 하지만, 생각처럼 쉽지 않았다. MBR 영역의 GRUB 설정이야 어느정도 생각은 했었지만, 하루 반나절을 삽질을 하는데 보냈다.
원인은 우분투에서는 EXT4 을 사용했고, 페도라에서는 EXT3 를 사용했다. 그런데, GRUB 에서는 EXT4 파일 시스템을 인식하지 못해서, 그 안에 있는 커널과 부팅에 필요한 파일들을 액세스할 수 없는 문제였다. 결국 우분투 역시 EXT3 로 설치했고, 결과는 성공이었다.
참고로 설치한 파티션 정보는 다음과 같다.
파티션 | 파일시스템 | OS |
---|---|---|
/dev/sda1 | EXT3(/) | 우분투 |
/dev/sda2 | SWAP | 공통 사용 |
/dev/sda3 | EXT3(/) | 페도라 |
내가 하고 하려고 했던 것은 두 개의 리눅스를 멀티 부팅하려는 것이었고, 그 절차는 다음과 같다 .
- 우분투 설치
- 페도라 설치
- GRUB 설정 파일 수정(/boot/grub/menu.lst)
title Ubuntu root (hd0,0) kernel /boot/vmlinuz-2.6.35-22-generic ro root=/dev/sda1 initrd /boot/initrd.img-2.6.35-22-generic
콘솔에서 백스페이스 소리끄기
.bashrc 파일에 다음과 같이 추가한다.
setterm -blength 0
콘솔 해상도 조정하기
가장 최상의 해상도로 설정하기 위해, GRUB 설정 파일에 다음을 추가한다.
vga=0x31B // menu.lst 파일에 추가
Latch up 메세지 해석하기
Latch up 이라 함은 DTV 프로그램이 어떠한 이유로 인해 더 이상 실행할 수 없을 경우를 의미한다. 여기서는 크게 2 가지로 분류해 볼 수 있다.
Application 에 의한 경우
흔히 노란색 화면이 뜨는 경우가 Application 에 의한 경우다. 다시 말해 DTV 프로세스가 죽은 경우이다. 여기서 노란색 화면이 뜨는 것은 DTV 디버깅 라이브러리 때문이다. 또한 이때, Register Dump 를 출력해주는 것 또한 디버깅 라이브러리(lgexc) 때문이다.
Register Dump 로그를 보고, Latch up 이 발생한 위치와 원인을 파악할 수 있어야 한다. 예시를 통해 알아보도록 하자.
[000616.966264] Get segment violation fault at 0x0, path /home/work/wjkim.kim/gp4-mtk/src/apps/prj/dvb_bb_mtk5395 ==== REGISTER map ==== a1/r0 0x00000001 a2/r1 0x00000000 a3/r2 0x00000800 a4/r3 0x0000000b v1/r4 0x5e3523b8 v2/r5 0x00080800 v3/r6 0x5e3523b8 v4/r7 0x5e35230c v5/r8 0x00000000 v6/r9 0x00000000 v7/r10 0x00000003 v8/r11 0x00000ff0 ip/r12 0x00000800 sp/r13 0x5e352148 lr/r14 0x40cb84dc pc/r15 0x40cb78b4 epc : 40cb78b4 ra : 40cb84dc Exception Stack(Size=0x100, CRC32=0xe55e964f) 0x5e352148(0000): 00000000 00000000 00000000 00000000 ................ 0x5e352158(0010): 00000000 00000000 00000000 00000000 ................ 0x5e352168(0020): 00000000 00000000 00000000 00000000 ................ 0x5e352178(0030): 00000000 00000000 00000000 00000000 ................ 0x5e352188(0040): 00000000 00000000 00000000 00000000 ................ 0x5e352198(0050): 00000000 00000000 00000000 00000000 ................ 0x5e3521a8(0060): 00000000 00000000 00000000 00000000 ................ 0x5e3521b8(0070): 00000000 00000000 00000000 00000000 ................ 0x5e3521c8(0080): 00000000 00000000 00000000 00000000 ................ 0x5e3521d8(0090): 00000000 00000000 00000000 00000000 ................ 0x5e3521e8(00a0): 00000000 00000000 00000000 00000000 ................ 0x5e3521f8(00b0): 00000000 00000000 00000000 00000000 ................ 0x5e352208(00c0): 00000000 00000000 00000000 00000000 ................ 0x5e352218(00d0): 00000000 00000000 00000000 00000000 ................ 0x5e352228(00e0): 00000000 00000000 00000000 00000000 ................ 0x5e352238(00f0): 00000000 00000000 00000000 00000000 ................ 40cb7874 1785c103 STRNE r12,[r5,r3,LSL #2] 40cb7878 e2833001 ADD r3,r3,#1 40cb787c e3530004 CMP r3,#4 40cb7880 1afffff9 BNE 0x40cb786c 40cb7884 e1a00005 MOV r0,r5 40cb7888 e5841038 STR r1,[r4,#0x38] 40cb788c eb000237 BL 0x40cb8170 40cb7890 e3a00000 MOV r0,#0 40cb7894 eaffffe4 B 0x40cb782c 40cb7898 e3530000 CMP r3,#0 40cb789c 1affffe1 BNE 0x40cb7828 40cb78a0 e1a02802 MOV r2,r2,LSL #16 40cb78a4 e5901038 LDR r1,[r0,#0x38] 40cb78a8 e1a02822 MOV r2,r2,LSR #16 40cb78ac e3a00001 MOV r0,#1 40cb78b0 e012c310 ANDS r12,r2,r0,LSL r3 ** 40cb78b4 14915004 LDRNE r5,[r1],#4 40cb78b8 1084c103 ADDNE r12,r4,r3,LSL #2 40cb78bc e2833001 ADD r3,r3,#1 40cb78c0 158c5004 STRNE r5,[r12,#4] 40cb78c4 e3530010 CMP r3,#0x10 40cb78c8 1afffff8 BNE 0x40cb78b0 40cb78cc e2120a02 ANDS r0,r2,#0x2000 40cb78d0 05841038 STREQ r1,[r4,#0x38] 40cb78d4 0affffd4 BEQ 0x40cb782c 40cb78d8 e3a00000 MOV r0,#0 40cb78dc eaffffd2 B 0x40cb782c 40cb78e0 e3a00001 MOV r0,#1 40cb78e4 eaffffd0 B 0x40cb782c 40cb78e8 e2530005 SUBS r0,r3,#5 40cb78ec 13a00001 MOVNE r0,#1 40cb78f0 e3530001 CMP r3,#1 40cb78f4 13530005 CMPNE r3,#5 >> Stack Trace for C functions, stack [0x5db55000-0x5e354000] >> [000: sp=0x5e352148, pc=0x40cb78b4] >> [001: sp=0x5e352148, pc=0x40cb84dc] >> List of PCs in stack [0x5e352148-0x5e354000] >> [092: sp=0x5e3522b8, pc=0x40db8db0] >> [095: sp=0x5e3522c4, pc=0x40db8db0] >> [099: sp=0x5e3522d4, pc=0x40db7fd0] >> [105: sp=0x5e3522ec, pc=0x00080800,CM_GetVCHStatusRef()@/home/work/wjkim.kim/gp4-mtk/src/mw/cm/cm_nvm.c:938] >> [109: sp=0x5e3522fc, pc=0x40cb84dc] >> [111: sp=0x5e352304, pc=0x40019618] >> [123: sp=0x5e352334, pc=0x40cb7cd0] >> [126: sp=0x5e352340, pc=0x40a997d8] 000617.004909:tUiMain ] _sendMsgInternal(qid=0x0, msg=0x50c73980, msz=16) :: Error, caller = 0x00724394 >> [135: sp=0x5e352364, pc=0x0079b6f2,ucpTimerLoop()@/home/yjh/workspace/4_DMPRMERGED/dmpr_merge_178/Source/ucp_engine/ucp_internal.c:421] >> [148: sp=0x5e352398, pc=0x40a997d8] >> [151: sp=0x5e3523a4, pc=0x40cb7608] >> [166: sp=0x5e3523e0, pc=0x40a9d794] >> [171: sp=0x5e3523f4, pc=0x0079b6f4,ucpTimerLoop()@/home/yjh/workspace/4_DMPRMERGED/dmpr_merge_178/Source/ucp_engine/ucp_internal.c:422] >> [172: sp=0x5e3523f8, pc=0x0079b6f4,ucpTimerLoop()@/home/yjh/workspace/4_DMPRMERGED/dmpr_merge_178/Source/ucp_engine/ucp_internal.c:422] >> [310: sp=0x5e352620, pc=0x40a9d794] >> [315: sp=0x5e352634, pc=0x0079b6f4,ucpTimerLoop()@/home/yjh/workspace/4_DMPRMERGED/dmpr_merge_178/Source/ucp_engine/ucp_internal.c:422] >> [316: sp=0x5e352638, pc=0x0079b6f4,ucpTimerLoop()@/home/yjh/workspace/4_DMPRMERGED/dmpr_merge_178/Source/ucp_engine/ucp_internal.c:422] >> [453: sp=0x5e35285c, pc=0x40cb821c] >> [457: sp=0x5e35286c, pc=0x40a997d8] >> [459: sp=0x5e352874, pc=0x40cb8204] >> [470: sp=0x5e3528a0, pc=0x40a9c144] >> [471: sp=0x5e3528a4, pc=0x40a9c144] >> [477: sp=0x5e3528bc, pc=0x40a9978c] >> [481: sp=0x5e3528cc, pc=0x40a90288] >> [487: sp=0x5e3528e4, pc=0x40ced480] >> [542: sp=0x5e3529c0, pc=0x40d8ecb0] >> [543: sp=0x5e3529c4, pc=0x40d51c44] >> [584: sp=0x5e352a68, pc=0x40000000] >> [586: sp=0x5e352a70, pc=0x40000000] >> [588: sp=0x5e352a78, pc=0x40000000] >> [590: sp=0x5e352a80, pc=0x40000000] >> [593: sp=0x5e352a8c, pc=0x40b76f00] >> [646: sp=0x5e352b60, pc=0x40000000] >> [705: sp=0x5e352c4c, pc=0x40d51c34] >> [709: sp=0x5e352c5c, pc=0x40d519d0] >> [711: sp=0x5e352c64, pc=0x0003d424,__signal_handler()@/home/work/wjkim.kim/gp4-mtk/src/common/osa/linux/osadap/osa_exception.c:148] >> [745: sp=0x5e352cec, pc=0x40ced460] >> [818: sp=0x5e352e10, pc=0x40a9d794] >> [821: sp=0x5e352e1c, pc=0x0079b6f4,ucpTimerLoop()@/home/yjh/workspace/4_DMPRMERGED/dmpr_merge_178/Source/ucp_engine/ucp_internal.c:422] >> [823: sp=0x5e352e24, pc=0x40a912fc] >> [831: sp=0x5e352e44, pc=0x40a9d794] >> [835: sp=0x5e352e54, pc=0x40a912cc] >> [933: sp=0x5e352fdc, pc=0x40d82f28] >> [1361: sp=0x5e35368c, pc=0x0079b6e0,ucpTimerLoop()@/home/yjh/workspace/4_DMPRMERGED/dmpr_merge_178/Source/ucp_engine/ucp_internal.c:416] >> [1370: sp=0x5e3536b0, pc=0x40a997a8] >> [1371: sp=0x5e3536b4, pc=0x40a997d8] >> [1372: sp=0x5e3536b8, pc=0x40cb809c] >> [1373: sp=0x5e3536bc, pc=0x0079b6f4,ucpTimerLoop()@/home/yjh/workspace/4_DMPRMERGED/dmpr_merge_178/Source/ucp_engine/ucp_internal.c:422] >> [1386: sp=0x5e3536f0, pc=0x0077bc64(0x0077bc64+0000x0), XmlPrologStateInitExternalEntity] >> [1391: sp=0x5e353704, pc=0x00800000(0x007ffd10+00x2f0), GestureRecognitionProcessor::~GestureRecognitionProcessor()] >> [1537: sp=0x5e35394c, pc=0x40dbbc14] 000617.486548:n1_003 ] [OSDPrint] [000616.966264] Get segment violation fault at 0x0, path /home/work/wjkim.kim/gp4-mtk/src/apps/prj/dvb_bb_mtk5395 ==== REGISTER map ==== a1/r0 0x00000001 a2/r1 0x00000000 a3/r2 0x00000800 a4/r3 0x0000000b v1/r4 0x5e3523b8 v2/r5 0x00080800 v3/r6 0x5e3523b8 v4/r7 0x5e35230c v5/r8 0x00000000 v6/r9 0x00000000 v7/r10 0x00000003 v8/r11 0x00000ff0 ip/r12 0x00000800 sp/r13 0x5e352148 lr/r14 0x40cb84dc pc/r15 0x40cb78b4 epc : 40cb78bkim.kim/gp4-mtk/src/mw/cm/cm_nvm.c:938]kim.kim/gp4-mtk/src/mw/cm/cm_nvm.c:938]
위와 같이 Latch up 메세지가 출력되었다고 했을 때, 가장 먼저 확인해야 하는 것이 발생한 위치이다. 위의 경우 Register Dump 를 통해 'pc=0x40cb78b4' 에서 발생했음을 알 수 있다. 잘못된 메모리(0x0) 주소를 참조했다.
그런데, 메모리 주소 값으로는 정확히 어디인지 알 수 없다. 먼저 코드 영역인지 확인하자!
$mipsel-linux-addr2line -e DVB-BB-BCM35233-DBG 40cb78b4
만일 코드 영역이라면, 아래와 같이 해당 소스코드 파일과 라인 수 까지 출력된다.
/home/work/wjkim.kim/src/mw/nm/src/nm_api.c:213
코드 영역이 아니면, 쓰레기 값이 나온다. 실제 '40cb78b4' 주소로 확인해본 결과, 쓰레기 값이 나왔다. 그러므로 코드영역이 아니다. 그렇다면, 메모리 영역이라 볼 수 있다. 메모리 맵을 봐야 하는데, 확인 방법은 다음과 같다.
- 보드를 부팅한다.
- DTV 프로세스의 PID 를 확인한다.
- /proc/PID 디렉토리 아래의 maps 라는 파일을 cat 으로 보자. 메모리 주소 영역과 그에 대응되는 share 라이브러리가 있을 것이다.
- 위의 주소 '0x40cb78b4' 가 대응되는 영역을 찾아보자! 대응되는 라이브러리가 있다면, DTV 프로세스는 해당 라이브러리 API 를 수행하다가 Latch up 이 발생한 것이다.
- 하지만, 이것으로는 문제의 원인을 파악하기 힘들다. Trace 정보를 따라가다 보면, 아래 메세지가 보인다.
>> [105: sp=0x5e3522ec, pc=0x00080800,CM_GetVCHStatusRef()@/home/work/wjkim.kim/gp4-mtk/src/mw/cm/cm_nvm.c:938]
정확한 코드의 위치까지 출력되어 있다. 그렇다면, 이보다 앞선 Trace 정보에서는 코드 위치가 표시되지 않았을까? 그것은 디버깅 심볼 정보가 제거된 라이브러리 형태로 되어있기 때문이다. 임베디드 시스템에서 사용하는 라이브러리(Glibc, Uclibc)들은 크기와 속도 때문에, 디버깅 심볼 정보를 제거하고, 최적화 옵션을 사용하여 빌드한다. 따라서 자세한 라이브러리 API 정보를 알 수 없는 것이다.
지금까지 얻은 정보를 가지고 Latch up 의 원인을 예측해보자!
- cm_nvm.c 의 938 번째 라인의 API 가 호출되었고, 그것은 share 라이브러리를 호출했다.
- 실행도중, Latch up 이 발생했다.
여기서 우리가 확인해볼 수 있는 부분은 코드 영역인 cm_nvm.c 파일이다. 그렇다면, 이 함수를 시작으로 디버깅을 시작하면 되겠다.
Kernel 에 의한 경우
Kernel panic 으로 인한 경우, 노란화면이 안뜰 수 있다. 사용자 프로세스가 아닌 Kernel 자체가 죽어버린 경우이기 때문이다. 하지만, 커널 또한 하나의 Application 이기 때문에 로그 메세지를 통해 원인을 파악할 수 있다.
아래와 같이 예를 들어보자.
[ 122.085000] Oops[#1]: [ 122.085000] Cpu 0 [ 122.085000] $ 0 : 00000000 00000000 814b2e80 00000000 [ 122.085000] $ 4 : 00000000 814ca12c 8183f320 e11aafd0 [ 122.085000] $ 8 : 00000020 80555cd0 81422600 00000000 [ 122.085000] $12 : 00000000 2ab1a020 00000000 00000000 [ 122.085000] $16 : 814b2e6c 00000001 814ca11c e1269afc [ 122.085000] $20 : e1269be8 e12484f8 814ca12c 814ca11c [ 122.085000] $24 : 00000000 805a4730 [ 122.085000] $28 : 81180000 81181b90 00000000 e11b435c [ 122.085000] Hi : 0000001c [ 122.085000] Lo : 6cc60100 [ 122.085000] epc : e12485b8 dbus_usbos_qdeq+0xc0/0x12c [wl] Tainted: P [ 122.085000] ra : e11b435c dbus_usbos_unlink+0x98/0xcc [wl] [ 122.085000] Status: 31008c02 KERNEL EXL [ 122.085000] Cause : 0080000c [ 122.085000] BadVA : 00000000 [ 122.085000] PrId : 00019750 (MIPS 74K) [ 122.085000] Modules linked in: wl(P) bcm_usbshim [ 122.085000] Process ifconfig (pid: 501, threadinfo=81180000, task=81194000, tls=2aacf420) [ 122.085000] Stack : 00000000 00000000 7f8e02e0 807b0000 e11b42c4 e12b0000 e11b8a9c e11b435c [ 122.085000] e11b8a9c e11c415c 814ca100 00000003 814ca100 e11b42c4 814ca12c 814ca100 [ 122.085000] e11aaf60 000005e4 00008914 7f8e02e0 00000000 e11b4e30 31008c03 0000001c [ 122.085000] 8142261c 00000008 815da680 81181c60 815da680 8183f320 e11aaf60 e11b4f20 [ 122.085000] 000005e4 00008914 7f8e02e0 00000000 81181c60 e11a9e64 80ff9400 e11aa0c0 [ 122.085000] ... [ 122.085000] Call Trace: [ 122.085000] [<e12485b8>] dbus_usbos_qdeq+0xc0/0x12c [wl] [ 122.085000] [<e11b435c>] dbus_usbos_unlink+0x98/0xcc [wl] [ 122.085000] [<e11b4e30>] dbusos_stop+0xe4/0x184 [wl] [ 122.085000] [<e11b4f20>] dbus_usbos_intf_down+0x20/0x30 [wl] [ 122.085000] [<e11a9e64>] bcm_rpc_call+0x168/0x19c [wl] [ 122.085000] [<e1212dc0>] wlc_bmac_write_shm+0x14c/0x16c [wl] [ 122.085000] [<e12310ac>] wlc_key_hw_init_all+0x5c/0x198 [wl] [ 122.085000] [<e11ef7c4>] wlc_init+0x358/0x9b4 [wl] [ 122.085000] [<e11dc3f8>] wlc_up+0x39c/0x614 [wl] [ 122.085000] [<e11c2cd0>] wl_up+0x74/0xcc [wl] [ 122.085000] [<e11c3248>] wl_open+0x50/0xac [wl] [ 122.085000] [<8068e6bc>] dev_open+0xac/0x11c [ 122.085000] [<8068d9c4>] dev_change_flags+0xc8/0x1c0 [ 122.085000] [<806d02a8>] devinet_ioctl+0x2c4/0x78c [ 122.085000] [<8067e3d4>] sock_ioctl+0x22c/0x280 [ 122.085000] [<8048517c>] vfs_ioctl+0x3c/0xb4 [ 122.085000] [<80485534>] do_vfs_ioctl+0x340/0x370 [ 122.085000] [<804855b4>] sys_ioctl+0x50/0x8c [ 122.085000] [<8040bf44>] stack_done+0x20/0x3c [ 122.085000] [ 122.085000] [ 122.085000] Code: 2450ffec 8e040018 8e030014 <ac830000> ac640004 ae020014 ae020018 02201021 10400002 [ 122.338000] Kernel panic - not syncing: Fatal exception in process
역시 마찬가지로 가장 먼저 죽은 위치를 보자!
[ 122.085000] [<e12485b8>] dbus_usbos_qdeq+0xc0/0x12c [wl]
dbus_usbos_qdeq 함수를 수행하다 발생한 것을 알 수 있다.
Stagecraft 빌드하기
현재 DTV 프로세스 말고도, NM 과 같이 별도의 프로세스로 동작하는 것들이 있다. 이것들은 NM 처럼 별도로 컴파일되고, 생성된 바이너리만 epk 에 추가되는 형태다. 그중에 하나가 Stagecraft 라는 것인데, 이를 빌드하는 방법에 대해 설명한다.
$cd src/thirdparty_v1.5/Stagecraft/ # thirdparty 버전은 src 디렉토리 아래에서 make 를 치면 알 수 있다 $make $make install $cd FWStagecraft $./release.sh b230
빌드시간이 생각보다 오래 걸린다.