Chap 3 부트로더 (Bootloader)
1. Bootloader 임베디드장치의초기화를위해서사용되는 bootloader 에대해서알아보도록한다. Achro-i.MX6Q 는 u-boot 를이용한다. 1.1. Bootloader 임베디드시스템에 bootloader가존재하는이유는다음과같다. 일반적인 X86시스템에서는마더보드와 CPU가잘동작할수있도록초기화하는프로그램이보드에내장되어있다. 보통 CMOS BIOS를말한다. 컴퓨터가부팅될때, <Del> 키나 <F2> 키를입력하여 BIOS 설정부분으로들어가면컴퓨터시스템의하드웨어속성등을변경할수있다. 하지만임베디드시스템에서는이러한기능을하는부분을넣기가힘들다. CMOS의개발비용도비싸고컴퓨터처럼범용시스템으로사용될지아니면특수목적용으로사용될지모르기때문이다. 그래서일반적인 PC에서처럼부착된하드웨어 (Processor를포함한전체시스템 ) 를초기화해주는부분이필요하게되었다. 이것이 bootloader 이다. bootloader는전원이인가되면사용가능한하드웨어를초기화를시켜주고커널을메모리에올려서리눅스가부팅될수있도록해주는역할을한다. 1.2. bootloader 컴파일 보드에서 bootloader 가실행되려면 bootloader 를 ARM 시스템에맞도록빌드를해 야된다. 아래는 bootloader 소스를시스템에설치하여빌드하는과정을다룬다. 1.2.1. bootloader 소스준비제공된 bootloader 소스를컴파일하여 bootloader 바이너리파일을생성한다. <Host PC> root@ubuntu:/# mkdir /root/temp root@ubuntu:/# cp -a [Achro-Disc]/u-boot/u-boot.tar.bz2 /root/temp root@ubuntu:/# cd /root/temp root@ubuntu:~/temp# mkdir /work/ root@ubuntu:~/temp# mkdir /work/achroimx6q/ root@ubuntu:~/temp# tar xvf u-boot.tar.bz2 -C /work/achroimx6q/ root@ubuntu:~/temp# cd /work/achroimx6q/u-boot/ 2
1 mkdir /root/temp : 소스를복사할디렉터리를만든다. 2 cp -a [Achro-Disc]/u-boot/u-boot.tar.gz /root/temp 제공된디스크의 bootloader 소스를 /root/temp 디렉터리로복사한다. 3 cd /root/temp; mkdir /work; mkdir /work/achroimx6q 압축파일을복사한디렉터리로이동후소스를설치할디렉터리를생성한다. 4 tar xvf u-boot.tar.bz2 -C /work/achroimx6q 압축파일을 /work/achroimx6q 디렉터리에설치한다. 5 cd /work/achroimx6q/u-boot 생성된 bootloader 디렉터리로이동한다. 1.2.2. bootloader 컴파일 Achro-i.MX6Q 개발보드를위한컴파일과정은다음과같다. <Host PC> root@ubuntu:/work/achroimx6q/u-boot# make distclean root@ubuntu:/work/achroimx6q/u-boot# make clean root@ubuntu:/work/achroimx6q/u-boot# make achroimx_linux_sd_config Configuring for achroimx_linux_sd board... root@ubuntu:/work/achroimx6q/u-boot# make 1 make distclean / make clobber 이전에 bootloader 를설정했던환경값들을모두초기화시킨다. 2 make clean 이전에 make 과정에서생성된파일들을모두삭제한다. (*.bak, *.o, *.a 등 ) 3 make achroimx6q_config mkconfig 스크립트를호출 include/config.h, include/config.mk 파일을생성한다. 생성된 include/config.h 파일의내용은아래와같다. /* Automatically generated - do not edit */ #include <configs/achroimx6q.h> #include <asm/config.h> 3 3
include/configs/achroimx.h 에개발보드와관련된설정사항들을정의한다. #include <asm/arch/mx6.h> /* High Level Configuration Options */ #define CONFIG_ARMV7 /* This is armv7 Cortex-A9 CPU core */ #define CONFIG_MXC #define CONFIG_MX6Q #define CONFIG_MX6Q_SABREAUTO #define CONFIG_FLASH_HEADER #define CONFIG_FLASH_HEADER_OFFSET 0x400 #define CONFIG_MX6_CLK32 32768 #define CONFIG_SKIP_RELOCATE_UBOOT #define CONFIG_ARCH_CPU_INIT #undef CONFIG_ARCH_MMU /* disable MMU first */ #define CONFIG_L2_OFF /* disable L2 cache first*/ #define CONFIG_MX6_HCLK_FREQ 24000000...( 생략 )... 그리고생성된 include/config.mk 파일의내용은아래와같다. ARCH = arm CPU = arm_cortexa8 BOARD = achroimx VENDOR = huins SOC = mx6 위에서 ARCH, CPU, BOARD, CPU 에대입된내용은 Makefile 파일에추가한내 용중에서 $(MKCONFIG) 에전달한파라미터임을알수있고, 이들파라미터의 의미는다음과같다. 4
첫번째 : arm 아키텍처가무엇인지를나타낸다. 어떤크로스컴파일러를사용할것인지결정된다. (arm-none-linux-gnueabi) 어떤라이브러리를사용할것인지결정된다. (arch/arm/lib) 두번째 : arm_cortexa8 CPU가무엇인지를나타낸다.(ARM Cortex A8 코어를사용 ) 어떤라이브러리를사용할것인지결정된다. (cpu/arm_cortexa8) 세번째 : achroimx 위의 CPU를적용한개발보드가무엇인지를나타낸다. 네번째 : huins 어떤라이브러리를사용할것인지결정된다. (board/huins/achroimx6q/*) 다섯번째 : mx6 SOC가무엇인지를나타낸다. 어떤라이브러리를사용할것인지결정된다. (cpu/arm_cortexa8/mx6/*) 위내용에서 CPU 에대한속성을어느정도이해했다면, 해당프로세서칩에대 한상세한내용은제조사홈페이지에서확인할수있다. 1.3. bootloader 기록 컴파일된 bootloader 바이너리를시스템에퓨징 ( 기록 ) 하도록한다. 1.3.1. dd 명령어를이용한방법 SD card 에 bootloader 를기록하는방법으로 dd 명령어를사용한다. emmc 와 SD card, SPI-nor 에 bootloader 가기록이되어있지않는경우사용한다. 1 SD card 삽입 bootloader를기록하기위해서 SD card를 card reader기에삽입하고 Host PC의 USB port에삽입한다. dmesg 명령어를통해서어떠한이름으로마운트되었는지확인한다. <Host PC> root@ubuntu:/work/achroimx6q/u-boot# dmesg 5 5
X root@ubuntu File Edit View Terminal Help [90669.193290] usb 3-6: new high-speed USB device number 19 using xhci_hcd [90669.210430] usb 3-6: New USB device found, idvendor=14cd, idproduct=125b [90669.210439] usb 3-6: New USB device strings: Mfr=1, Product=3, SerialNumber=2 [90669.210444] usb 3-6: Product: AutoRUN/Partition [90669.210448] usb 3-6: Manufacturer: Generic [90669.210452] usb 3-6: SerialNumber: 125B20100804 [90669.211234] scsi9 : usb-storage 3-6:1.0 [90671.206345] scsi 9:0:0:0: Direct-Access Mass Storage Device PQ: 0 ANSI: 0 CCS [90671.207439] sd 9:0:0:0: Attached scsi generic sg3 type 0 [90671.362298] sd 9:0:0:0: [sdc] 7744511 512-byte logical blocks: (3.96 GB/3.69 GiB) [90671.362504] sd 9:0:0:0: [sdc] Write Protect is off [90671.362510] sd 9:0:0:0: [sdc] Mode Sense: 03 00 00 00 [90671.362682] sd 9:0:0:0: [sdc] No Caching mode page found [90671.362688] sd 9:0:0:0: [sdc] Assuming drive cache: write through [90671.364215] sd 9:0:0:0: [sdc] No Caching mode page found [90671.364224] sd 9:0:0:0: [sdc] Assuming drive cache: write through [90671.368944] sdc: sdc1 [90671.369881] sd 9:0:0:0: [sdc] No Caching mode page found [90671.369889] sd 9:0:0:0: [sdc] Assuming drive cache: write through [90671.369895] sd 9:0:0:0: [sdc] Attached SCSI removable disk 2 bootloader 기록 dd명령을통해서 SD card에기록을한다. 여기서 if는기록할파일이름이되며, of 는기록될위치인데이위치는위에서 dmesg에서검색된위치를사용한다. sdc로등록이되었으면 of의위치는 /dev/sdc이다. <Host PC> root@ubuntu:/work/achroimx6q/u-boot# dd if=u-boot.bin of=/dev/sd[x] bs=512 seek=2 skip=2 conv=fsync 473+1 records in 473+1 records out 242428 bytes (242 kb) copied, 0.00205108 s, 118 MB/s 3 부팅 퓨징이완료되면 Host PC 에서 SDcard 를제거하고 Target Board 에삽입한다. Switch 에전원을인가하고부팅한다. 6
그리고동작은아래와같다. 우선보드에전원이인가되면, CPU는 BL0의내용을읽는다. BL0는 irom( 내부 ROM) Code라고볼리며, CPU 제조사가해당프로세서를만들때프로그램되어내장된다. BL0가시작되면, 우선 OM(Operating Mode) 를체크한다. OM은주로 DIP Switch 형태로구성되며본교재에서다루는 Achro-i.MX6Q Mode는 sd boot과 emmc boot이다. 즉, Dip Switch(OM) 의상태에따라 emmc로부팅을할것인지, 아니면 sd card로부팅을할것인지가결정이 7 7
된다. Boot Mode 설정핀은아래와같다. (Boot Mode 설정을위한 Dip Switch 는 LCD 와 Text LCD 사이에보면있다.) 이후 BL1의위치를확인하여데이터를읽게되는데, BL0에는현재사용하는 Target 보드에대한내용이포함되어있지않아하드웨어를초기화시킬수없으므로, Bootloader 내용을 RAM으로복사할수없다. 그래서 BL0는 CPU가시스템을초기화시키고부팅하기위한시스템하드웨어정보와초기화할수있는코드가들어있는 BL1을내부 RAM(SRAM or iram) 에올려해당내용을토대로 cpu와그주변장치들을초기화한다.( 내부 RAM은용량이작아 Bootloader를통째로올릴수없으므로 BL1을올려 BL2를올릴수있는선행작업을하게됨 ) 그다음 BL2인나머지 Bootloader를 DRAM으로복사한다. 이후 cpu는 DRAM에적재된 Bootloader 코드를읽어앞으로우리가사용하게될부트로더인 u-boot를실행한다. 8
현재사용하고있는 u-boot는 2009.08 버전으로부트이미지앞 1024bytes에는 ROM Header가들어가있다. 현재 Freescale I.MX6Q는그앞의 Header 부분을제외한나머지부분을사용하기때문에앞의 ROM Header를제외한나머지부분을적재해주어야한다. 그래서 dd라는명령어를사용하여이미지를적재할때 seek와 skip이라는옵션이들어가게된다. skip에는입력파일에서처리하지않고통과할크기를지정하고, seek에는출력파일에기록하지않고통과할크기를지정하면된다. bs=512로한번에 512byte씩읽는다는뜻이다. 즉, 입력파일에서 skip -> 2 * 512 = 1024bytes 만큼처리하지않고통과하고출력파일에서는 seek -> 2 * 512 = 1024bytes 만큼기록하지않고통과하게된다. skip 옵션으로 u-boot 앞에있는 1024bytes 크기를제외하고나머지부분을 seek 옵션을이용해서 sd card의 1024byte(0X400) 뒤에서부터기록하겠다는뜻이다. 그리고마지막옵션인 fsync는 file 간의 metadata의 Sync를맞추겠다는뜻이다. (CPU의자세한메모리설명을보고싶으면, CD1의 datasheet\cpu\imx6dqrm_i.mx 6Dual 6Quad Applications Processor Reference Manual.pdf 파일을참조하길바람 ) 4 TFTP 다운로드이제 Bootloader를올렸으니 TFTP를이용하여이미지파일을다운로드할것이다. TFTP는 Ethernet 통신이므로 TFTP를하기위해서는일반적으로 Lan Cable이필요하다. Lan Cable에는 Direct Cable과 Cross Cable 두종류가있다. Direct Cable 의경우 Hub에서 Peer(PC, Printer, Server 등 ) 로연결하는일반적인용도로사용되며, Cross Cable은 Peer to Peer (PC to PC 또는 Hub to Hub) 연결에사용된다. 일반적으로 Cross Cable 을이용하여보드와 PC 1:1 통신을할수도있다. 하지만 9 9
Half/Full Duplex 설정문제로장애가발생할수있다. Duplex 설정은서버와같은시스템의네트워크인터페이스와 Switch 포트간, Switch 포트와 Router 인터페이스간서로일치해야한다. 100/10 Ethernet Card와 Switch의경우상호 auto-negotiation을수행하여 speed와 duplex mode를자동적으로설정하게되지만장비간 auto-negotiation protocol의차이로인해제대로연결되지않는경우가발생한다. 이외에도여러가지문제가있지만, 이러한문제들로인해 PC와 Target 보드간의 1:1통신보다는공유기또는허브를거쳐서통신하는방법을권장한다. 이제 TFTP 관련설정을해보도록하겠다. 우선 Bootloader의 Prompt에서 print 또는 pri라고쳐본다. 그러면 Boot 및 Kernal Command에관해서나올것이다. <Target board> Achro i.mx6q > pri 10
TFTP 통신을하기위해선 serverip, ipaddr, ethaddr 을맞춰야한다. serverip 는이 미지를다운로드할 Host PC 의 IP 이며 ipaddr 은 Target Board 의 IP 이다. 그리고 ethaddr 은마찬가지로 Host PC 의 MAC address 이다. ** 세팅값들이위처럼뜨지않는경우 SD card 를 SD Formatter 나다른파티션 삭제프로그램으로깔끔하게비우고다시진행하면된다. 우선다루는방법을알아보자. 우선위의환경변수를추가해주기위해선 set 또는 setenv라는명령어를이용하면된다. 그리고그뒤에환경변수명을적어주고뒤에파라미터를적어주면된다. <Target board> Achro i.mx6q > setenv huins 1234 결과를보면제일아랫줄에 huins 1234가추가된것을볼수있다. 그리고만약공백이들어가는긴명령문을입력해야하는경우 를이용한다. 이번에는만든환경변수 huins의값을바꿔보겠다. 이럴경우환경변수명은똑같이적어주고, 뒤의값만바꿔주면된다. 아래처럼명령어를적어주면 huins의값이 1234에서 very good huins로바뀌게된다. 11 11
<Target board> Achro i.mx6q > setenv huins very good huins' 만약환경변수를지우고싶다면아래와같은방법을사용하면된다. <Target board> Achro i.mx6q > setenv huins 12
결과를보면알수있듯이환경변수명뒤에아무런값도적지않으면값이지워지게된다. 자이제는 TFTP 통신을위해 serverip, ipaddr, ethaddr을바꿔보겠다. Host PC에서 ifconfig라는명령어로 IP를확인해보자. <Host PC> root@ubuntu:/# ifconfig 만약 Host PC의 IP가잡혀있지않다면 LAN Cable이제대로연결되어있는지확인해보고, 아래의방법으로 IP를다시세팅해준다. 인터넷이연결되지않은상태에서가상머신을켜게되면잡히지않을수있다. <Host PC> root@ubuntu:/# vi /etc/network/interfaces 아래처럼 eth0 관련내용을적어주고저장한다. 아래내용은대략인터넷서비스재 실행시 eth0 인터페이스를자동으로올리는데자동으로 ip 를얻어온다는뜻이다. 그래도안잡힌다면 Image 다운로드용으로만사용하므로고정 IP 를사용해도된다. 13 13
<Host PC> root@ubuntu:/# ifconfig eth0 192.168.1.201 현재 PC에연결된 ethernet card는 eth0로잡혀있으며추가적으로 LAN Card를꼽아서사용한다면 eth1, eth2.. 가될것이다. 여기서 serverip는 192.168.1.201이되는것이고 ethaddr은 00:0c:29:b0:04:ca이다. 그리고 ipaddr의경우 Target Board의 IP인데이것은 GatewayIP를맞춰주기위해 IP의네부분중앞의세부분만맞춰주면된다. 즉, ipaddr은 192.168.1.xxx로뒤의숫자는다른 IP와겹치지않는숫자로적어주면된다. <Target board> Achro i.mx6q > setenv serverip 192.168.1.201 Achro i.mx6q > setenv ipaddr 192.168.1.70 Achro i.mx6q > setenv ethaddr 00:0c:29:b0:04:ca Achro i.mx6q > save 이렇게환경변수를세팅후저장을하지않고전원을끄면세팅값들이모두지워 진다. 때문에 save 또는 saveenv 명령어로저장을해주도록하자. IP 세팅까지끝났고이제이미지를다운로드할차례이다. 그런데기존의 u-boot source build 를통해서생성된 u-boot.bin 은앞에 ROM Header 라는 padding data 14
가있다. 때문에 Padding data를잘라낸새로운이미지를만들어야한다. 아까 SD Card에이미지를써넣을때의방법을이해했다면아래명령어가이해될것이다. Host PC의 u-boot 폴더에서아래의명령어를실행하자. <Host PC> root@ubuntu:/work/achroimx6q/u-boot/# dd if=u-boot.bin of=u-boot.bin.padding bs=512 skip=2 conv=fsync root@ubuntu:/work/achroimx6q/u-boot/# cp u-boot.bin.padding /tftpboot TFTP를이용해서다운로드하고 SD/MMC의 0x400에써넣을것이기때문에 seek 옵션은사용하지않는다. 이미지가만들어졌으면그것을 /tftpboot 폴더로복사한다. 그리고다시 Target Board로돌아와서아래의명령을실행한다. <Target board> Achro i.mx6q > tftp 10800000 u-boot.bin.padding 만약 Loading : 부분에서 #### 이나오지않고 TTTTTTT 또는 TT#TTTT# 이런형태의응답이나오게되면통신이제대로되지않고있는것이다. 제대로전송이되었다면 done이라는메시지와전송한크기가출력이된다. 이렇게전송을받게되면이미지는 DRAM에올라가게된다. 이이미지는재부팅을하게되면지워진다. 그러므로 SD/MMC에복사를해서유지를하도록하자. SD/MMC로복사하는명령어는다음과같다. SD Card 에 Write 할경우 <Target board> Achro i.mx6q > mmc dev 0 Achro i.mx6q > mmc write 10800000 2 600 I.MX6Q 보드의 SD/MMC slot 이총 4 개가있다. 그중 0 번은 Micro_sd_card slot 이 고 2 번의경우 emmc 로되어있다. 따라서 mmc dev 0 은 Micro_sd_card 를뜻하고 mmc dev 2 의경우 emmc 를뜻한다. 우리는 Micro_sd_card 에 Write 를하고진행을 15 15
하도록하겠다. 우리가여태까지진행한내용은아래와같다. TFTP 를이용해서다운을받고그것을다시 SD/MMC 에덮어씌우고다시부팅을 하게되면최종적으로수정이된 Bootloader 가부팅이되는것이다. 16