u-boot 를 이용해서 타겟보드에 부트로더를 포팅하는 방법에 대해서 설명하고 있다.
현재 나온 부트로더 프로그램들이 많이 있지만, 내가 생각하기에 u-boot 가 가장 많이 사용되고 있는 것으로 보인다.
여기서는 u-boot 1.1.4 를 기준으로 설명할 것이다. 포팅할 타겟보드는 smdk2410 보드이다. 내가 이 문서를 만들게된 계기는 다른 때와는 조금 남다르다. 나는 그전까지 부트로더의 모든 소스 프로그램들은 모두 개발자 손으로 만들어야 한다고 생각했었다. 하지만, 이번일을 계기로 조금 생각이 달라졌다.

리눅스가 인기를 끌게된 가장 큰 이유는 바로 오픈소스라는 정책때문이다. 우리가 흔히 생각하기에 오픈소스는 그냥 공짜라고 생각하기 쉬운데, 이것은 오픈소스가 가진 지극히 작은 부분만을 본 것이다. 소스가 오픈되어 있기 때문에, 나 같은 생초보 개발자의 경우, 기존에 만들어져 있는 프로그램의 코드를 볼 수 있다. 코드를 보면서, 작동 루틴을 이해할 수 있고, 또한 응용할 수 있다.

임베디드 분야에서 리눅스에 대해서 불만 섞인 목소리가 나왔었다. 그것은 바로 기술지원의 부재였다. 이것처럼 기존의 코드 사용에 있어 아무런 책임도 요구할 수 없다. 서론이 너무 길었으니, 바로 본론으로 들어가도록 하겠다.

준비해야 할 것들

여기서는 smdk2410 이라는 타겟보드를 기준으로 설명하고 있지만, 만일 다른 보드를 기준으로 포팅해야 한다고 해도 공통적으로 반드시 알아야 할 사항들에 대해서 언급할 것이다. SMDK 2410 보드 포팅하기 에서도 일부 언급하고 있지만, u-boot 에서는 기본적으로 지원하고 있다.
그래서 별다른 설정없이도, 부트로더 초기화는 가능하다.
하지만 여기서 문제는 flash 이다. u-boot 에서는 Am29LV800BB 를 기준으로 만들어져 있다. 하지만 여기서는 Intel 28F128J3A flash 를 사용할 것이다.
준비해야 할 것은 다음과 같다.

  1. Flash Datasheet
  2. U-boot 소스코드(분석을 위해)

포팅하기

현재 u-boot 에서는 수많은 타겟보드의 환경을 지원하고 있는데, 다행스럽게도(?) 그중에서 28F128J3A Flash 를 사용하는 보드들이 있다.
검색창에서 'INTEL_ID_28F128J3A' 로 검색하면, 몇 가지 보드들이 나온다. 그중에서 가장 가깝다고 할 수 있는 lubbock 보드를 선택했다.

/board/lubbock 아래에 있는 flash.c 파일을 /board/smdk2410 아래로 복사한다. 이전에 있던 파일은 이름을 수정한다.

/include/configs 아래에 smdk2410.h 파일을 아래와 같이 수정한다.

#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   // flash 가 2개지만, 섹터의 수는 128 개로 동일하지만, 섹터 크기는 2배로 늘었다. 
 
#define CFG_MAX_FLASH_SECT      (128)
 
#define CFG_ENV_ADDR            (PHYS_FLASH_1 + 0x40000)      // u-boot 의 환경변수를 저장할 주소
#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

위의 수정사항은 Datasheet 를 참조한다. 위에서 가장 중요한 것은 PHYS_FLASH_SECT_SIZE 이다. smdk2410 보드에서 사용하고 있는 flash Datasheet 를 보면, 128 Mbit 의 경우, 총 128 개의 블럭으로 되어있고, 각 블럭은 128 Kbyte 로 되어 있다. 이것은 flash 가 1개 있을 때의 경우이다.
실제로 같은 flash 2 개를 합쳐서 사용한다. 또한 32 bit mode 로 동작하기 때문에 섹터양은 늘어났지만, 섹터수는 그대로 128 개 이다.
모두 수정했다면, 컴파일 후에 flash 에 쓰고, 부팅을 한다. 그리고 'saveenv' 명령을 실행한다. 에러없이 명령이 수행되었다면, 성공이다.

포팅시에 고려할 것들

먼저 포팅하려는 타겟보드에 대해서 완전히 숙지한다.
예를 들어 flash 의 경우, u-boot 에서 같은 모델의 flash 를 사용했는지 검색해본다. 만일 존재한다면, 위의 방법으로 포팅한다. 예를 들어 없다면, 그중에 가장 비슷한 flash 모델을 찾아서 실제 flash 의 Datasheet 와 비교해가면서 파일을 수정한다.

포팅이라는 것은 새로운 것을 만드는 것이 아니다. 기존에 있는 것을 내 입맛에 맞게 고치는 것이다. 그렇기 때문에 굳이 처음부터 모두 만들 필요는 없다.
내가 원하는 것이 이미 만들어져서 인터넷의 어딘가에 있을 지도 모를 일이다.

명령어 만들기

u-boot 는 사용자의 편의를 위해 여러가지 명령어(command)를 제공하고 있다. 이런 명령어를 사용자가 추가나 삭제가 가능하다.
SMDK 2410 보드 포팅하기 에서 flash 에 write 하기 위해서 여러가지 명령어를 조합해야 했다. 여기서는 간단한 명령어 한번으로 flash 에 write 하는 명령어를 사용할 것이다.

명령어 설명
fbb flash 에 부트로더를 write 한다
fkb flash 에 커널이미지를 write 한다
frb flash 에 램디스크를 write 한다

u-boot 의 소스코드에 앞에서 정의한 명령어를 추가시켜줘야 한다. 파일은 common/cmd_brp.c 이다.

/*
 * bootrom programming routine
 *       by ghcstop
 *
 * usage:
 *
 *      prompt> brp
 *        이렇게 하면 default로 /tftpboot/u-boot.bin을 가져와서 플래쉬 앞쪽에 부트코드를 쓴다
 *      prompt> brp godori2410
 *        이렇게 하면 default로 /tftpboot/godori2410을 가져와서 플래쉬 앞쪽에 부트코드를 쓴다
 */
 
#include <common.h>
 
#include <command.h>
#include <asm/processor.h>
#include <asm/io.h>
 
/***************************************************/
 
int do_fbb(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
        int rc = 1;
        char buffer[100];
 
        if (argc  > 2)
        {
                printf ("Usage:\n%s\n", cmdtp->usage);
                return 1;
        }
 
        if (argc < 2)   /* fbb 만 입력 햇을 경우   */
        {
            sprintf (buffer,"tftp 30000100 u-boot.bin ");
            rc = run_command(buffer, flag);
 
            if ( rc >= 0 )
            {
                printf("correct u-boot image!!!\n");
                /*run_command("protect off 1:0-126",bd, flag);*/
                /* ghcstop fix */
                run_command("protect off 1:0", flag);
                run_command("erase 1:0", flag);
                sprintf (buffer,"cp.b 30000100 00000000 %s ",getenv("filesize"));
                run_command(buffer, flag);
                /*run_command("protect on 1:0-126 ",bd, flag);*/
                /* ghcstop fix */
                run_command("protect on 1:0", flag);
            }
        }
 
        if (argc == 2)    /* fbb 0x3333  등을 입력햇을 대  */
        {
            sprintf (buffer,"tftp 30000100 %s ",argv[1]);
            rc = run_command(buffer, flag);
 
            if ( rc >= 0 )
            {
                printf("correct u-boot image!!!\n");
                /*run_command("protect off 1:0-126",bd, flag);*/
                /* ghcstop fix */
                run_command("protect off 1:0", flag);
                run_command("erase 1:0", flag);
                sprintf (buffer,"cp.b 30000100 00000000 %s ",getenv("filesize"));
                run_command(buffer, flag);
                /*run_command("protect on 1:0-126 ",bd, flag);*/
                /* ghcstop fix */
                run_command("protect on 1:0", flag);
            }
        }
 
        return 0;
}
 
 
int do_fkb(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
        int rc = 1;
        char buffer[100];
 
        if (argc  > 2)
        {
                printf ("Usage:\n%s\n", cmdtp->usage);
                return 1;
        }
 
        if (argc < 2)
        {
            sprintf (buffer,"tftp 33000000 uImage");
            rc = run_command(buffer, flag);
 
            if ( rc >= 0 )
            {
                printf("correct kernel image!!!\n");
                /*run_command("protect off 1:0-126",bd, flag);*/
                /* ghcstop fix */
                run_command("protect off 1:2-4", flag);
                run_command("erase 1:2-4", flag);
                sprintf (buffer,"cp.b 33000000 00080000 %s ",getenv("filesize"));
                run_command(buffer, flag);
                /*run_command("protect on 1:0-126 ",bd, flag);*/
                /* ghcstop fix */
                run_command("protect on 1:2-4", flag);
            }
        }
 
        if (argc == 2)
        {
            sprintf (buffer,"tftp 33000000 %s ",argv[1]);
            rc = run_command(buffer, flag);
 
            if ( rc >= 0 )
            {
                printf("correct kernel image!!!\n");
                /*run_command("protect off 1:0-126",bd, flag);*/
                /* ghcstop fix */
                run_command("protect off 1:2-4", flag);
                run_command("erase 1:2-4", flag);
                sprintf (buffer,"cp.b 33000000 00080000 %s ",getenv("filesize"));
                run_command(buffer, flag);
                /*run_command("protect on 1:0-126 ",bd, flag);*/
                /* ghcstop fix */
                run_command("protect on 1:2-4", flag);
            }
        }
 
        return 0;
}
/***************************************************/
 
 
int do_frb(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
{
        int rc = 1;
        char buffer[100];
 
        if (argc  > 2)
        {
                printf ("Usage:\n%s\n", cmdtp->usage);
                return 1;
        }
 
        if (argc < 2)
        {
            sprintf (buffer,"tftp 30800000 ramdisk.fat ");
            rc = run_command(buffer, flag);
 
            if ( rc >= 0 )
            {
                printf("correct ramdisk image!!!\n");
                /*run_command("protect off 1:0-126",bd, flag);*/
                /* ghcstop fix */
                run_command("protect off 1:5-100", flag);
                run_command("erase 1:5-100", flag);
                sprintf (buffer,"cp.b 30800000 00140000 %s ",getenv("filesize"));
                run_command(buffer, flag);
                /*run_command("protect on 1:0-126 ",bd, flag);*/
                /* ghcstop fix */
                run_command("protect on 1:5-100", flag);
            }
        }
 
        if (argc == 2)
        {
            sprintf (buffer,"tftp 30800000 %s ",argv[1]);
            rc = run_command(buffer, flag);
 
            if ( rc >= 0 )
            {
                printf("correct ramdisk image!!!\n");
                /*run_command("protect off 1:0-126",bd, flag);*/
                /* ghcstop fix */
                run_command("protect off 1:5-100", flag);
                run_command("erase 1:5-100", flag);
                sprintf (buffer,"cp.b 30800000 00140000 %s ",getenv("filesize"));
                run_command(buffer, flag);
                /*run_command("protect on 1:0-126 ",bd, flag);*/
                /* ghcstop fix */
                run_command("protect on 1:5-100", flag);
            }
        }
 
        return 0;
}
/***************************************************/
 
U_BOOT_CMD(
	fbb,	2,	1,	do_fbb,
	"fbb - flash write to u-boot ex> fbb - get default 'u-boot.bin' image to 0x30000100\n",
	"fbb - fdd is flash write to boot loader\n"
);
 
 
U_BOOT_CMD(
	fkb,	2,	1,	do_fkb,
	"fkb - flash write to linux kernel ex> fkb - get default 'uImage' image to 0x33000000\n",
	"fkb - fkb is flash write to kernel image\n"
);
 
 
 
U_BOOT_CMD(
	frb,	2,	1,	do_frb,
	"frb - flash write to linux kernel ex> frb - get default 'ramdisk.fat' image to 0x30800000\n",
	"frb - frb is flash write to ramdisk image\n"
);

각 명령어들의 루틴을 간략히 분석하면, 명령어 이외에 들어오는 인자값을 수를 가지고 루틴을 수행한다. 명령어 이외에 인자값이 하나도 없으면, 명령어에서 기본적으로 지정하는 파일이름과 위치에 flahs write 를 한다.
만일 명령어 이외에 인자값이 있으면, 인자값으로 주어진 파일 이름을 tftp 로 다운로드 받아서 특정한 위치에 flash write 한다.
'U_BOOT_CMD' 함수는 부트로더 프롬프트에서 'help' 명령시에 나오는 도움말을 등록시켜준다.
u-boot 컴파일을 하기전에 위에서 만든 cmd_brp.c 파일을 common/Makefile 에 추가해주어야 한다.

COBJS   = main.o ACEX1K.o altera.o bedbug.o circbuf.o \
          cmd_ace.o cmd_autoscript.o \
          cmd_bdinfo.o cmd_bedbug.o cmd_bmp.o cmd_boot.o cmd_bootm.o \
          cmd_cache.o cmd_console.o \
          cmd_date.o cmd_dcr.o cmd_diag.o cmd_display.o cmd_doc.o cmd_dtt.o \
          cmd_eeprom.o cmd_elf.o cmd_ext2.o \
          cmd_fat.o cmd_fdc.o cmd_fdos.o cmd_flash.o cmd_fpga.o \
          cmd_i2c.o cmd_ide.o cmd_immap.o cmd_itest.o cmd_jffs2.o \
          cmd_load.o cmd_log.o \
          cmd_mem.o cmd_mii.o cmd_misc.o cmd_mmc.o \
          cmd_nand.o cmd_net.o cmd_nvedit.o \
          cmd_pci.o cmd_pcmcia.o cmd_portio.o \
          cmd_reginfo.o cmd_reiser.o cmd_scsi.o cmd_spi.o cmd_universe.o \
          cmd_usb.o cmd_vfd.o  cmd_brp.o \         <<<-------  추가하기
          command.o console.o devices.o dlmalloc.o docecc.o \
          environment.o env_common.o \
          env_nand.o env_dataflash.o env_flash.o env_eeprom.o \
          env_nvram.o env_nowhere.o \
          exports.o \
          flash.o fpga.o ft_build.o \
          hush.o kgdb.o lcd.o lists.o lynxkdi.o \
          memsize.o miiphybb.o miiphyutil.o \
          s_record.o serial.o soft_i2c.o soft_spi.o spartan2.o spartan3.o \
          usb.o usb_kbd.o usb_storage.o \
          virtex2.o xilinx.o
  • computer/rtcclab/u-boot_를_이용한_보드_포팅하기.txt
  • Last modified: 3 years ago
  • by likewind