Hardware Porting
초심 프로젝트의 다섯 번째 주제로 직접 타겟 보드에 포팅을 해봄으로써 하드웨어를 이해하도록 한다.
| 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 하면 된다.