초심 프로젝트의 다섯 번째 주제로 직접 타겟 보드에 포팅을 해봄으로써 하드웨어를 이해하도록 한다.
Hardware | SMDK2410, EZ-5 |
Software | Toolchain etc |
포팅과 관련해서 여기서 언급하지 않는 내용들은 U-BOOT 를 이용한 보드 포팅하기, SMDK 2410 보드 포팅하기 를 참고하기 바란다.
여기서 다룰 것은 크게 세가지이다. 부트로더와 커널, 그리고 파일 시스템의 포팅이다.
각각, u-boot 와 kernel(linux), vpos 를 이용해서 포팅한다. 여기서는 총 3 가지의 툴 체인을 사용한다. 하나의 툴 체인을 사용하면 좋겠지만, 각 소스코드 마다 컴파일러에 의존적인 코드가 있기 때문에 각각의 컴파일 환경을 만들어주어야 한다.
항목 | 설명 | 설치 경로 | |
u-boot | eldk-arm-linux-x86.iso(1.1.4) 또는 aesoptool_gcc334_glibc233.tar.gz(1.1.5 이상) | /usr/local/arm_920 또는 /korea-dokdo | |
kernel(linux) | eldk-arm-linux-x86(2.4.18) | /usr/local/arm_920 | |
vpos | arm_200701.16.tgz | /usr/local/arm |
※ 한가지 유의할 점은 eldk-arm-linux-x86.iso 설치시에 설치 경로를 /usr/local/arm_920 으로 해주어야 한다는 점이다.
※ 이것은 U-BOOT 를 이용한 보드 포팅하기, SMDK 2410 보드 포팅하기 에서의 설치 경로와 다르다. .bash_profile 을 다음과 같이 수정한다.
CROSS_COMPILE=arm_920TDI- PATH=$PATH:$HOME/bin:/usr/local/arm/usr/bin export PATH CROSS_COMPILE
개발환경 구축하기
앞의 두 개의 문서에서 설명한 내용에서 새롭게 업데이트 된 내용 만을 다룬다.
u-boot
버전이 1.1.5 이 되면서, U-BOOT 를 이용한 보드 포팅하기 에서 설치했던 arm_920TDI 컴파일러로는 컴파일이 불가능해졌다. 이유는 gcc 버전이 낮기 때문이다.
1.1.4 버전까지는 컴파일이 가능하기 때문에, 굳이 최신버전을 사용하지 않겠다면 예전 방법대로 컴파일하면 된다. 여기서는 현재 최신버전인 1.1.6 을 기준으로 설명한다.
1.1.6 을 컴파일하기 위해서 http://www.aesop-embedded.org/download.html 에서 툴 체인을 다운로드 받는다. 설치 방법은 다음과 같다.
#mkdir /korea-dokdo #cd /korea-dokdo #tar xzf aesoptool_gcc334_glibc233.tar.gz -C /korea-dokdo
path 를 걸어주기 위해서 .bash_profile 을 수정한다.
PATH=$PATH:$HOME/bin:/korea-dokdo/aesoptool/gcc-3.3.4-glibc-2.3.3/arm-linux/bin export PATH
이제 u-boot 를 컴파일하기 위한 준비가 끝났다.
kernel
SMDK2410 에 현재 포팅되어 있는 kernel 이 2.4.18 이기 때문에 기존의 툴 체인(arm_920TDI)으로 컴파일해야만 한다.
툴 체인 설치 및 커널 컴파일 방법은 SMDK 2410 보드 포팅하기 를 참고하기 바란다.
vpos
vpos 를 위한 툴 체인은 /usr/local/arm 에 설치된다. 다음과 같이 설치한다.
#tar xzf arm_200701.16.tgz -C /usr/local #cd /usr/local #ln -s arm arm-sf
path 를 걸어주기 위해 .bash_profile 을 수정한다.
PATH=$PATH:$HOME/bin:/usr/local/arm/bin export PATH
host pc
제목은 host pc 라고 적었지만, redhat 9 에서 tftp 와 dhcp 서비스를 하기 위한 설정에 대해서 설명한다.
여기서는 tftp 의 경우, RPM 으로 설치하고 dhcp 의 경우는 source 설치를 할 것이다.
tftp
redhat 9 CD 로부터 tftp 패키지를 찾아 설치한다.
#rpm -ivh tftp-0.32-4.i386.rpm #rpm -ivh tftp-server-0.32-4.i386.rpm
/etc/xinetd.d/tftp 을 다음과 같이 수정한다.
service tftp { disable = no socket_type = dgram protocol = udp wait = yes user = root server = /usr/sbin/in.tftpd server_args = -s /tftpboot per_source = 11 cps = 100 2 flags = IPv4 }
dhcp
컴파일 및 설치는 DHCP 서버 구축하기 를 참고하기 바란다.
다음은 /etc/dhcpd.conf 의 설정이다. 참고로 host pc 의 IP 는 166.104.30.15 이고, 타겟 보드의 IP 는 166.104.30.26 이다.
# # Sample configuration file for ISC dhcpd for Debian # # $Id: HardwarePorting,v 1.1 2013/06/07 06:20:43 root Exp root $ # # The ddns-updates-style parameter controls whether or not the server will # attempt to do a DNS update when a lease is confirmed. We default to the # behavior of the version 2 packages ('none', since DHCP v2 didn't # have support for DDNS.) ddns-update-style none; # option definitions common to all supported networks... option domain-name "kevin.tcom-dtvro.com"; option domain-name-servers 211.111.136.2; default-lease-time 600; max-lease-time 7200; # If this DHCP server is the official DHCP server for the local # network, the authoritative directive should be uncommented. #authoritative; # Use this to send dhcp log messages to a different log file (you also # have to hack syslog.conf to complete the redirection). log-facility local7; # No service will be given on this subnet, but declaring it helps the # DHCP server to understand the network topology. #subnet 10.152.187.0 netmask 255.255.255.0 { #} # This is a very basic subnet declaration. #subnet 10.254.239.0 netmask 255.255.255.224 { # range 10.254.239.10 10.254.239.20; # option routers rtr-239-0-1.example.org, rtr-239-0-2.example.org; #} # This declaration allows BOOTP clients to get dynamic addresses, # which we don't really recommend. #subnet 10.254.239.32 netmask 255.255.255.224 { # range dynamic-bootp 10.254.239.40 10.254.239.60; # option broadcast-address 10.254.239.31; # option routers rtr-239-32-1.example.org; #} # A slightly different configuration for an internal subnet. allow bootp; subnet 166.104.30.0 netmask 255.255.255.0 { range 166.104.30.25 166.104.30.26; # option domain-name-servers ns1.internal.example.org; # option domain-name "internal.example.org"; option routers 166.104.30.1; option broadcast-address 166.104.30.255; default-lease-time 600; max-lease-time 7200; group { host redwood62.kevin.tcom-dtvro.com { hardware ethernet 11:22:33:44:55:66; # 타겟 보드 MAC Address fixed-address 166.104.30.26; # 타겟 보드 IP option root-path "/tftpboot"; } } } # Hosts which require special configuration options can be listed in # host statements. If no address is specified, the address will be # allocated dynamically (if possible), but the host-specific information # will still come from the host declaration. #host passacaglia { # hardware ethernet 0:0:c0:5d:bd:95; # filename "vmunix.passacaglia"; # server-name "toccata.fugue.com"; #} # Fixed IP addresses can also be specified for hosts. These addresses # should not also be listed as being available for dynamic assignment. # Hosts for which fixed IP addresses have been specified can boot using # BOOTP or DHCP. Hosts for which no fixed address is specified can only # be booted with DHCP, unless there is an address range on the subnet # to which a BOOTP client is connected which has the dynamic-bootp flag # set. #host fantasia { # hardware ethernet 08:00:07:26:c0:a5; # fixed-address fantasia.fugue.com; #} # You can declare a class of clients and then do address allocation # based on that. The example below shows a case where all clients # in a certain class get addresses on the 10.17.224/24 subnet, and all # other clients get addresses on the 10.0.29/24 subnet. #class "foo" { # match if substring (option vendor-class-identifier, 0, 4) = "SUNW"; #} #shared-network 224-29 { # subnet 10.17.224.0 netmask 255.255.255.0 { # option routers rtr-224.example.org; # } # subnet 10.0.29.0 netmask 255.255.255.0 { # option routers rtr-29.example.org; # } # pool { # allow members of "foo"; # range 10.17.224.10 10.17.224.250; # } # pool { # deny members of "foo"; # range 10.0.29.10 10.0.29.230; # } #}
컴파일
u-boot
컴파일 방법은 기존의 문서를 참고하기로 하고, 여기서는 최종 수정한 소스 파일 몇가지를 보이겠다.
다음은 include/configs/smdk2410.h 이다.
/* this must be included AFTER the definition of CONFIG_COMMANDS (if any) */ #include <cmd_confdefs.h> #define CONFIG_BOOTDELAY 3 /*#define CONFIG_BOOTARGS "root=ramfs devfs=mount console=ttySA0,9600" */ #define CONFIG_ETHADDR 11:22:33:44:55:66 # 수정 #define CONFIG_NETMASK 255.255.255.0 # 수정 #define CONFIG_IPADDR 166.104.30.26 # 수정 #define CONFIG_SERVERIP 166.104.30.15 # 수정 /*#define CONFIG_BOOTFILE "elinos-lart" */ /*#define CONFIG_BOOTCOMMAND "tftp; bootm" */ #if (CONFIG_COMMANDS & CFG_CMD_KGDB) #define CONFIG_KGDB_BAUDRATE 115200 /* speed to run kgdb serial port */ /* what's this ? it's not used anywhere */ #define CONFIG_KGDB_SER_INDEX 1 /* which serial port to use */ #endif /* * Miscellaneous configurable options */ #define CFG_LONGHELP /* undef to save memory */ #define CFG_PROMPT "FAT81 # " /* 수정 */ #define CFG_CBSIZE 256 /* Console I/O Buffer Size */ #define CFG_PBSIZE (CFG_CBSIZE+sizeof(CFG_PROMPT)+16) /* Print Buffer Size */ #define CFG_MAXARGS 16 /* max number of command args */ #define CFG_BARGSIZE CFG_CBSIZE /* Boot Argument Buffer Size */ ... ... ... /*----------------------------------------------------------------------- * FLASH and environment organization # 수정 및 추가 */ #define CFG_MAX_FLASH_BANKS 1 /* max number of memory banks */ #define PHYS_FLASH_SIZE 0x02000000 #define PHYS_FLASH_BANK_SIZE 0x02000000 #define PHYS_FLASH_SECT_SIZE 0x00040000 #define CFG_MAX_FLASH_SECT (128) #define CFG_ENV_ADDR (PHYS_FLASH_1 + 0x40000) #define CFG_ENV_SIZE 0x40000 #define CFG_ENV_SECT_SIZE 0x40000 /* timeout values are in ticks */ #define CFG_FLASH_ERASE_TOUT (5*CFG_HZ) /* Timeout for Flash Erase */ #define CFG_FLASH_WRITE_TOUT (5*CFG_HZ) /* Timeout for Flash Write */ #define CFG_ENV_IS_IN_FLASH 1 #endif /* __CONFIG_H */
다음은 board/smdk2410/flash.c 이다.
unsigned long flash_init (void) { int i; ulong size = 0; for (i = 0; i < CFG_MAX_FLASH_BANKS; i++) { switch (i) { case 0: flash_get_size ((FPW *) PHYS_FLASH_1, &flash_info[i]); flash_get_offsets (PHYS_FLASH_1, &flash_info[i]); break; case 1: # 수정 break; default: panic ("configured too many flash banks!\n"); break; } size += flash_info[i].size; } /* Protect monitor and environment sectors */ flash_protect ( FLAG_PROTECT_SET, CFG_FLASH_BASE, CFG_FLASH_BASE + monitor_flash_len - 1, &flash_info[0] ); flash_protect ( FLAG_PROTECT_SET, CFG_ENV_ADDR, CFG_ENV_ADDR + CFG_ENV_SIZE - 1, &flash_info[0] ); return size; }
다음은 lib_arm/armlinux.c 이다.
SHOW_BOOT_PROGRESS (10); print_image_hdr (hdr); /* 앞에서 ramdisk.fat 생성시에 mkimage 를 이용해서 만든 커널 헤더를 읽어서 램디스크 정보 출력 */ data = addr + sizeof (image_header_t); len = ntohl (hdr->ih_size); #ifdef CONFIG_HAS_DATAFLASH /* 실행 안됨 */ if (addr_dataflash (addr)) { read_dataflash (data, len, (char *) CFG_LOAD_ADDR); data = CFG_LOAD_ADDR; } #endif memcpy((char *)0x30800000, (char *)data, len); // 추가할 부분 (data : 0x140040, len : 0x34ec24) if (verify) { ulong csum = 0; printf (" Verifying Checksum ... "); csum = crc32 (0, (char *) data, len); if (csum != ntohl (hdr->ih_dcrc)) { printf ("Bad Data CRC\n"); SHOW_BOOT_PROGRESS (-12); do_reset (cmdtp, flag, argc, argv); } printf ("OK\n"); }
kernel
SMDK 2410 보드 포팅하기 를 참고하기 바란다.
vpos
압축을 풀고 컴파일하면 된다.
#tar xzf vpos.tar.gz #make clean #make
에러없이 컴파일 되었다면, images 디렉토리에 elf 와 binary 파일이 생성되었을 것이다.
vpos.bin 파일을 SMDK2410 test program 을 이용해서 NOR Flash 0x0 번지에 write 하면 된다.