/* elf32-littlearm.lds 파일 */

//이 부분은 arm-linux-ld가 만들어 낼 최종 결과 파일의 포맷을 나타낸다.
//즉, little endian 포맷의 파일을 생성할 것인지,
//big endian 포맷의 파일을 생성할 것인지를 결정하는 역할을 한다.

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")

//이 부분은 최종 결과 파일이 동작할 CPU의 architecture를 나타낸다.
//즉, 이 파일은 ARM CPU 상에서 동작한다는 의미이다.

OUTPUT_ARCH(arm)

//최종 결과 파일의 시작 지점을 나타낸다.
//즉, 여기서 파일의 시작 지점은 reset_handler가 된다.
//reset_handler는 Cstartup.s 파일에 정의되어 있다.

ENTRY(reset_handler)

//SECTIONS{ ... }부분은 링커(arm-linux-ld)가 입력 파일들의 섹션들을
//결과 파일의 어떤 섹션들로 위치시킬지를 결정하는 역할을 한다.

SECTIONS
{
    .text : {          //프로그램의 코드영역
        _stext = .;      //코드영역의 시작주소를 makefile로 부터 가져온다.
        *(.text)        //모든 입력 파일들(*)의 .text 섹션을 결과 파일의 .text 섹션에 위치시킨다.
        *(.rodata)      //readonly 파일들을 .text 섹션에 위치시킨다.
        *(.rodata*)    //그외 모든 데이터들을 .text 섹션에 위치시킨다.
        . = ALIGN(4);  //현재의 위치에서 4 바이트 단위로 놓겠다는 의미이다.
                                 // 즉, 4바이트 단위로 메모리를 정렬한다.

         _etext = . ;    //코드영역의 끝을 현재 위치포인트로 하겠다는 의미이다.
    }

    //데이터 영역
     //코드영역 시작주소부터 코드영역의 크기만큼 더한다음 주소 즉, 코드영역 다음 주소
    .data : AT ( ADDR (.text) + SIZEOF (.text) ) {  
        _sdata = .;
        *(.vectors)    //모든 입력 파일의 벡터 테이블을 데이터 영역에 포함
        *(.data)       //모든 입력 파일의 초기화 된 데이터를 데이터 영역에 포함
        _edata = .;
    }

     //bss 영역
     //noload = 적재하지 않는다. 
    .bss (NOLOAD) : { 
        . = ALIGN(4);
        _sbss = .;
        *(.bss)         //모든 입력 파일의 bss영역을 출력파일의 bss영역에 포함한다.
        _ebss = .;
    }
}
end = .;

u-boot-2009.03 버전을 기준으로 진행한다. 이전 버전과 별반 차이가 없어 보이긴 하지만.. 웬지 최신을 좋아하는 관계로다가;;;

./api/
-
./api_example/
-
./board/
- 타겟보드에 종속적인 코드들이 들어가있다.
./common/
-
./cpu/
- 프로세서에 종속적인 코드
./disk/
./doc/
- 관련 문서
./drivers/
- 디바이스 드라이버
./examples/
-
./fs/
- 파일 시스템
./include/
- 컴파일 할 때 include할 헤더파일들
./include/configs/
- 보드에 대한 설정
./lib_*/
- 각 아키텍쳐에 따른 디렉도리
- 여러개가 있다.
./libfdt/
-
./nand_spl/
-
./net/
- 네트워크 관련 코드
./onenand_ipl/
-
./post/
./tools/
- 바이너리 이미지 등을 만드는 툴

아직 미지(?)의 디렉토리도 있고, 정확히 이해하지 못하는 디렉토리나 잘못 할고 있는 디렉토리도 있다. 따라서 이 글은 수정을 통해서 업데이트 해야겠다.

출처 : http://inusing.tistory.com/17
U- Boot의 Makefile에는 다음과 같은 항목이 존재하며, 
이 항목은 U-Boot를 어떤 CPU로 사용하는 Board용으로 빌드 할 것인지를 결정합니다.


[1~7 
항 목별 역할] 
U-Boot를 빌드 할 Configuration의 이름 
U-Boot를 특정 보드를 위하여, 빌드 할 수 있도록 해주는 구분자입니다. 실제로 U-Boot 컴파일 시 “make smdk2410_config”라고 입력하면, U-Boot는 SMDK2410 보드용으로 컴파일 될 수 있도록 설정됩니다.

“make smdk2410_config”를 입력하면, 
위의 Makefile에서는 mkconfig라는 유틸리티를 호출하여 mkconfig에 ③~⑦ 번 항목을 인자로 입력합니다. mkconfig 스크립트는 이 인자를 입력 받아서 컴파일 환경 설정을 진행하게 됩니다.
$(@:_config=) 항목의 경우 위의 “smdk2410_config” 라는 항목이며, 여기서 “smdk2410”이라는 항목만을 인자로 받아서, mkconfig에 전달하게 됩니다.
“smdk2410”이라는 항목은 mkconfig에서 BOARD_NAME을 설정하는데 사용되며, 
다음은 mkconfig에서 이 인자를 전달 받아서 Board Name을 설정하는 항목입니다.

while [ $# -gt 0 ] ; do 
case "$1" in 
--) shift ; break ;; 
-a) shift ; APPEND=yes ;; 
-n) shift ; BOARD_NAME="${1%%_config}" ; shift ;; 
*) break ;; 
esac 
done 
[ "${BOARD_NAME}" ] || BOARD_NAME="$1" 
[ $# -lt 4 ] && exit 1 
[ $# -gt 6 ] && exit 1 
echo "Configuring for ${BOARD_NAME} board..."

위의 BOARD_NAME이라는 항목에는 “smdk2410_config”에서 “_config”를 제외한 “smdk2410”을 $1 인자로 받아 처리하는 mkconfig 스크립트의 루틴입니다. 이 루틴 때문에 U-Boot 컴파일 시 “make smdk2410_config”을 입력하면,"Configuring for smdk2410 board..."라는 메시지가 화면에 출력되게 됩니다.

CPU의 아키텍처를 입력하는 부분으로 ARM, MIPS등 CPU 아키텍처들 별로 상이하게 사용되는 어셈블러 랭귀지를 구분하기 위해 만들어진 항목입니다. mkconfig에 두 번째 인자로 전달되며 [ARCH] 라는 항목으로 인식됩니다. 이 항목은 다음과 같은 디렉터리를 컴파일 하도록 설정합니다. 

- U-Boot의 “include/” 디렉터리 내의 헤더 파일들에 대한 컴파일 항목
ㆍ“include/asm-[ARCH]/” 를 “include/asm/” 이라는 이름으로 심볼릭 링크를 생성하고 이 항목들을 이 항목들을 소스 컴파일 시 include시킵니다.. 
ㆍ“include/asm-[ARCH]/proc- armv/”를 “proc-armv/”라는 이름으로 심볼릭 링크를 생성하고 이 항목들을 소스 컴파일 시에 include시킵니다. - U-Boot 소스의 루트 디렉터리에 대한 컴파일 항
ㆍ“lib_[ARCH]/” 디렉터리를 컴파일 합니다. 

CPU의 종류를 입력하는 부분으로 ARM 계열 CPU의 각 계열들을 구분하기 위해서 만들어진 항목입니다. 각 CPU 계열별로 특화된 항목에 대한 부분이 담겨있습니다. mkconfig에 세 번째 인자로 전달되며 [CPU] 라는 항목으로 인식됩니다. 이 항목은 다음과 같은 이름의 디렉터리를 컴파일 하도록 명령합니다. 

- U-Boot 소스의 “cpu/” 디렉터리에 대한 컴파일 항목 
“cpu/[CPU]/” 디렉터리를 컴파일 합니다. 

Board의 이름을 입력하는 항목으로 Board의 종류에 따라 특화된 항목에 대한 부분이 담겨있습니다. mkconfig에 네 번째 인자로 전달되며, [BOARD] 라 는 항목으로 인식됩니다. 이 항목은 다음과 같은 이름의 디렉터리를 컴파일 하도록 명령합니다. 

- U-Boot 소스의 “/board” 디렉터리에 대한 컴파일 항목 “board/[BOARD]/” 디렉터리를 컴파일 합니다.

Board를 제조한 Vendor에 대한 이름을 입력하는 항목으로 한 벤더에서 여러 가지의 Board를 출시했을 경우, 편리하게 분류 하기 위하여 만든 항목 입니다. 특정한 벤더가 없을 경우 “NULL”로 처리하면 자동으로 ⑤번 에서 설명한 항목만을 가지고 컴파일 합니다. 

- U-Boot 소스의 “board/” 디렉터리에 대한 컴파일 항목 
“board/[VENDOR]/[BOARD]/” 디렉터리를 컴파일 합니다.


SoC(이하 System On Chip)의 모델명을 입력하는 항목으로, 각 CPU 아키텍처와 계열을 탑재한 각 CPU 벤더의 SoC에 담겨있는 특화된 기능을 지원하기 위해 만들어진 항목입니다. mkconfig에 여섯 번째 인자로 전달되며,[SoC] 라는 항목으로 인식됩니다. 이 항목은 다음과 같은 이름의 디렉터리를 컴파일 하도록 명령합니다. 

- U-Boot 소스의 “cpu/” 디렉터리에 대한 컴파일 항목
“cpu/[CPU]/[SoC]/” 디렉터리를 컴파일 합니다. 

- U-Boot의 “include/” 디렉터리 내의 헤더 파일들에 대한 컴파일 항목 
“include/asm-[ARCH]/[SoC]/” 를 “asm/arch/”라는 이름으로 심볼릭 링크를 생성하고 이 항목들을 이 항목들을 소스 컴파일 시에 include 시킵니다.

출처 : http://blog.naver.com/hirou6/80107355464

u-boot 소스 코드

Board.C

start.s에서 start_armboot()로 제어가 넘어왔다.  이 함수는 board.c에 정의되어있다.

board.c를 보도록 하자.  board.c는 /lib_arm/에 위치해 있다.

/*
 * (C) Copyright 2002
 * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
 *
 * (C) Copyright 2002
 * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
 * Marius Groeger <mgroeger@sysgo.de>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include <common.h>
#include <command.h>
#include <malloc.h>
#include <devices.h>
#include <version.h>
#include <net.h>

#ifdef CONFIG_DRIVER_SMC91111
#include "../drivers/smc91111.h"
#endif
#ifdef CONFIG_DRIVER_LAN91C96
#include "../drivers/lan91c96.h"
#endif

#if (CONFIG_COMMANDS & CFG_CMD_NAND)
void nand_init (void);
#endif

ulong monitor_flash_len;

#ifdef CONFIG_HAS_DATAFLASH
extern int  AT91F_DataflashInit(void);
extern void dataflash_print_info(void);
#endif

#ifndef CONFIG_IDENT_STRING
#define CONFIG_IDENT_STRING ""
#endif

const char version_string[] =
 U_BOOT_VERSION" (" __DATE__ " - " __TIME__ ")"CONFIG_IDENT_STRING;

#ifdef CONFIG_DRIVER_CS8900
extern void cs8900_get_enetaddr (uchar * addr);
#endif

#ifdef CONFIG_DRIVER_RTL8019
extern void rtl8019_get_enetaddr (uchar * addr);
#endif

/*
 * Begin and End of memory area for malloc(), and current "brk"
 */
static ulong mem_malloc_start = 0;
static ulong mem_malloc_end = 0;
static ulong mem_malloc_brk = 0;

static
void mem_malloc_init (ulong dest_addr)
{
 mem_malloc_start = dest_addr;
 mem_malloc_end = dest_addr + CFG_MALLOC_LEN;
 mem_malloc_brk = mem_malloc_start;

 memset ((void *) mem_malloc_start, 0,
   mem_malloc_end - mem_malloc_start);
}

void *sbrk (ptrdiff_t increment)
{
 ulong old = mem_malloc_brk;
 ulong new = old + increment;

 if ((new < mem_malloc_start) || (new > mem_malloc_end)) {
  return (NULL);
 }
 mem_malloc_brk = new;

 return ((void *) old);
}

/************************************************************************
 * Init Utilities       *
 ************************************************************************
 * Some of this code should be moved into the core functions,
 * or dropped completely,
 * but let's get it working (again) first...
 */

 

 

/* console에 사용할 UART의 baud rate를 설정 */
static int init_baudrate (void)
{
 DECLARE_GLOBAL_DATA_PTR;

 uchar tmp[64]; /* long enough for environment variables */
 int i = getenv_r ("baudrate", tmp, sizeof (tmp));
 gd->bd->bi_baudrate = gd->baudrate = (i > 0)
   ? (int) simple_strtoul (tmp, NULL, 10)
   : CONFIG_BAUDRATE;

 return (0);
}

 


/* 설정된 정보를 화면에 출력한다. */
/* uboot version및 code, data, stack의 위치를 console에 출력 */
static int display_banner (void)
{
 printf ("\n\n%s\n\n", version_string);
 printf ("U-Boot code: %08lX -> %08lX  BSS: -> %08lX\n",
  _armboot_start, _bss_start, _bss_end);
#ifdef CONFIG_MODEM_SUPPORT
 puts ("Modem Support enabled\n");
#endif
#ifdef CONFIG_USE_IRQ
 printf ("IRQ Stack: %08lx\n", IRQ_STACK_START);
 printf ("FIQ Stack: %08lx\n", FIQ_STACK_START);
#endif

 return (0);
}

 

 


/*
 * WARNING: this code looks "cleaner" than the PowerPC version, but
 * has the disadvantage that you either get nothing, or everything.
 * On PowerPC, you might see "DRAM: " before the system hangs - which
 * gives a simple yet clear indication which part of the
 * initialization if failing.
 */
 /* DRAM셋팅후 화면에 출력 */
static int display_dram_config (void)
{
 DECLARE_GLOBAL_DATA_PTR;
 int i;

 puts ("RAM Configuration:\n");

 for(i=0; i<CONFIG_NR_DRAM_BANKS; i++) {
  printf ("Bank #%d: %08lx ", i, gd->bd->bi_dram[i].start);
  print_size (gd->bd->bi_dram[i].size, "\n");
 }

 return (0);
}

static void display_flash_config (ulong size)
{
 puts ("Flash: ");
 print_size (size, "\n");
}


/*
 * Breathe some life into the board...
 *
 * Initialize a serial port as console, and carry out some hardware
 * tests.
 *
 * The first part of initialization is running from Flash memory;
 * its main purpose is to initialize the RAM so that we
 * can relocate the monitor code to RAM.
 */

/*
 * All attempts to come up with a "common" initialization sequence
 * that works for all boards and architectures failed: some of the
 * requirements are just _too_ different. To get rid of the resulting
 * mess of board dependent #ifdef'ed code we now make the whole
 * initialization sequence configurable to the user.
 *
 * The requirements for any new initalization function is simple: it
 * receives a pointer to the "global data" structure as it's only
 * argument, and returns an integer return code, where 0 means
 * "continue" and != 0 means "fatal error, hang the system".
 */
typedef int (init_fnc_t) (void);

/* 포인터 변수는 값으로 주소를 갖는다. 각 주소에 가보면 함수가 존재할것이다. */
init_fnc_t *init_sequence[] = {
 cpu_init,  /* basic cpu dependent setup */
 board_init,  /* basic board dependent setup */
 interrupt_init,  /* set up exceptions */
 env_init,  /* initialize environment */
 init_baudrate,  /* initialze UART baudrate settings */
 serial_init,  /* serial communications setup */
 console_init_f,  /* stage 1 init of console */
 display_banner,  /* say that we are here */
 dram_init,  /* configure available RAM banks */
 display_dram_config, /* SDRAM start address, size를 console에 출력 */
#if defined(CONFIG_VCMA9)
 checkboard,
#endif
 NULL,
};

 

 

/* board와 관련된 모든 자원을 초기화 */
void start_armboot (void)
{
 /* Global_data.h에 명시  register volatile gd_t *gd asm("r8") */
 DECLARE_GLOBAL_DATA_PTR; 

 ulong size;
 init_fnc_t **init_fnc_ptr; /* 2차원 함수 배열. init_fnc_t *형은 *init_fnc_ptr의 데이터를 갖는다. 이는 어떠한 함수를 가리킬 것이고 이 함수들은 바로 위에 정의되어 있다. */
 char *s;
/* LCD controller설정 */
#if defined(CONFIG_VFD) || defined(CONFIG_LCD)
 unsigned long addr;
#endif

 /* 포인터 설정 */
 /* Pointer is writable since we allocated a register for it */
 gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
 /* compiler optimization barrier needed for GCC >= 3.4 */
 __asm__ __volatile__("": : :"memory");

 

 /* 메모리 클리어.  이 함수가 정의된 부분으로 가보면 gd부터 sizeof로 구한 영역만큼 0의 값을 넣어주는 함수이다. */
 memset ((void*)gd, 0, sizeof (gd_t));
 gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));


 /* global_data struct의 data를 0으로 초기화 한다. */
 /* gd->bd가리키는 영역을 gd_t크기만큼 0으로 만든다. */

 memset (gd->bd, 0, sizeof (bd_t)); 

 

 /* 모니터코드의 flash에서의 길이를 구한다. */
 monitor_flash_len = _bss_start - _armboot_start;

 

 /* board에 관련된 모든 자원을 초기화 한다. 바로 위의 함수배열로 정의되어 있다. 각각의 함수를 찾아보면서 어떤 동작을 하는지 알아보시길...  */
 /* cpu, board, interrupt, env, baudrate, serial, console, display, dram등등.. */
 for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
  if ((*init_fnc_ptr)() != 0) {
   /* error가 발생햇으니 reset하라고 출력하는 함수이다. */
   hang ();
  }
 }

 

 /* configure available FLASH banks */
 size = flash_init ();   /* flash를 초기화 하고 size를 얻는다. */
 display_flash_config (size); /* flash의 size를 console에 출력한다. */

#ifdef CONFIG_VFD
# ifndef PAGE_SIZE
#   define PAGE_SIZE 4096
# endif


 /*
  * reserve memory for VFD display (always full pages)
  */
 /* bss_end is defined in the board-specific linker script */
 addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
 size = vfd_setmem (addr);
 gd->fb_base = addr;
#endif /* CONFIG_VFD */

#ifdef CONFIG_LCD
# ifndef PAGE_SIZE
#   define PAGE_SIZE 4096
# endif


 /*
  * reserve memory for LCD display (always full pages)
  */
 /* bss_end is defined in the board-specific linker script */
 addr = (_bss_end + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
 size = lcd_setmem (addr);
 gd->fb_base = addr;
#endif /* CONFIG_LCD */

 

 /* armboot_start is defined in the board-specific linker script */
 mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);

 

#if (CONFIG_COMMANDS & CFG_CMD_NAND)
 puts ("NAND:");
 nand_init();  /* go init the NAND */
#endif

#ifdef CONFIG_HAS_DATAFLASH
 AT91F_DataflashInit();
 dataflash_print_info();
#endif

 

 /* initialize environment */
 env_relocate ();  /* flash에서 SDRAM으로 COPY한다. */

#ifdef CONFIG_VFD
 /* must do this after the framebuffer is allocated */
 drv_vfd_init();
#endif /* CONFIG_VFD */

 

 /* IP Address */
 gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");

 /* MAC Address */
 {
  int i;
  ulong reg;
  char *s, *e;
  uchar tmp[64];

  i = getenv_r ("ethaddr", tmp, sizeof (tmp));
  s = (i > 0) ? tmp : NULL;

  for (reg = 0; reg < 6; ++reg) {
   gd->bd->bi_enetaddr[reg] = s ? simple_strtoul (s, &e, 16) : 0;
   if (s)
    s = (*e) ? e + 1 : e;
  }
 }
 /* 설정되어 잇는 device가 있으면 초기화 한다.(i2c, LCD, keyboard) */
 devices_init (); /* get the devices list going. */

 jumptable_init ();

 console_init_r (); /* fully init console as a device */

 

#if defined(CONFIG_MISC_INIT_R)
 /* miscellaneous platform dependent initialisations */
 misc_init_r ();
#endif

 

 /* enable exceptions */
 /* interrupt를 enable한다. */
 enable_interrupts ();

 

 /* Perform network card initialisation if necessary */
#ifdef CONFIG_DRIVER_CS8900
 cs8900_get_enetaddr (gd->bd->bi_enetaddr);
#endif

#if defined(CONFIG_DRIVER_SMC91111) || defined (CONFIG_DRIVER_LAN91C96)
 if (getenv ("ethaddr")) {
  smc_set_mac_addr(gd->bd->bi_enetaddr);
 }
#endif /* CONFIG_DRIVER_SMC91111 || CONFIG_DRIVER_LAN91C96 */

 

 /* Initialize from environment */
 if ((s = getenv ("loadaddr")) != NULL) {
  load_addr = simple_strtoul (s, NULL, 16);
 }
#if (CONFIG_COMMANDS & CFG_CMD_NET)
 if ((s = getenv ("bootfile")) != NULL) {
  copy_filename (BootFile, s, sizeof (BootFile));
 }
#endif /* CFG_CMD_NET */

#ifdef BOARD_LATE_INIT
 board_late_init ();
#endif

 

 /* main_loop() can return to retry autoboot, if so just run it again. */
 for (;;) {
  main_loop (); /* (TOPDIR)/common/main.c   여기서 main()함수로 제어가 넘어가게된다.  */
 }

 /* NOTREACHED - no way out of command loop except booting */
}

 

 


void hang (void)
{
 puts ("### ERROR ### Please RESET the board ###\n");
 for (;;);
}

#ifdef CONFIG_MODEM_SUPPORT
/* called from main loop (common/main.c) */
extern void  dbg(const char *fmt, ...);
int mdm_init (void)
{
 char env_str[16];
 char *init_str;
 int i;
 extern char console_buffer[];
 static inline void mdm_readline(char *buf, int bufsiz);
 extern void enable_putc(void);
 extern int hwflow_onoff(int);

 enable_putc(); /* enable serial_putc() */

#ifdef CONFIG_HWFLOW
 init_str = getenv("mdm_flow_control");
 if (init_str && (strcmp(init_str, "rts/cts") == 0))
  hwflow_onoff (1);
 else
  hwflow_onoff(-1);
#endif

 for (i = 1;;i++) {
  sprintf(env_str, "mdm_init%d", i);
  if ((init_str = getenv(env_str)) != NULL) {
   serial_puts(init_str);
   serial_puts("\n");
   for(;;) {
    mdm_readline(console_buffer, CFG_CBSIZE);
    dbg("ini%d: [%s]", i, console_buffer);

    if ((strcmp(console_buffer, "OK") == 0) ||
     (strcmp(console_buffer, "ERROR") == 0)) {
     dbg("ini%d: cmd done", i);
     break;
    } else /* in case we are originating call ... */
     if (strncmp(console_buffer, "CONNECT", 7) == 0) {
      dbg("ini%d: connect", i);
      return 0;
     }
   }
  } else
   break; /* no init string - stop modem init */

  udelay(100000);
 }

 udelay(100000);

 /* final stage - wait for connect */
 for(;i > 1;) { /* if 'i' > 1 - wait for connection
      message from modem */
  mdm_readline(console_buffer, CFG_CBSIZE);
  dbg("ini_f: [%s]", console_buffer);
  if (strncmp(console_buffer, "CONNECT", 7) == 0) {
   dbg("ini_f: connected");
   return 0;
  }
 }

 return 0;
}

/* 'inline' - We have to do it fast */
static inline void mdm_readline(char *buf, int bufsiz)
{
 char c;
 char *p;
 int n;

 n = 0;
 p = buf;
 for(;;) {
  c = serial_getc();

  /*  dbg("(%c)", c); */

  switch(c) {
  case '\r':
   break;
  case '\n':
   *p = '\0';
   return;

  default:
   if(n++ > bufsiz) {
    *p = '\0';
    return; /* sanity check */
   }
   *p = c;
   p++;
   break;
  }
 }
}
#endif /* CONFIG_MODEM_SUPPORT */

이로써 U-Boot분석에 필요한 파일들을 살펴보았다.  이후 각자가 사용하게 될 보드에 맞게 포팅을 할때 지금 까지 봐왔던 큰 흐름을 기억하고 그에 따르는 줄기들을 잘 분석했다면 어떤 파일들을 수정해야 하는지 감이 올 것이다.  아울러 데이터시트를 참조하는것은 기본이라는 걸 기억하면서 u-boot에 대한 공부는 마무리하도록 하겠다.(머지않아 다시 골머리를 썩겠지만 ㅋ) 

 

6주 속성으로 배우기 무지 힘들다ㅠ.ㅠㅋ  시간 날때마다 추가적으로 분석하고 주석을 달아봐야겠다.

---------------

출처 : http://blog.naver.com/idrukawa/100054114578

memsetup.S

이전 start.S소스 중에서 cpu_init_crit()에서 memsetup으로 제어가 넘어왔다.

memsetup을 살펴보도록 하겠다.

/*
 *      A     EEEE  SSSS   OOO  PPPP
 *     A A    E     S     O   O P   P
 *    AAAAA   EEEE  SSSS  O   O PPPP
 *   A     A  E         S O   O P
 *   A     A  EEEE  SSSS   OOO  P
 *
 *  An Entertainment Solution On a Platform (AESOP) is a completely Open Source
 *  based graphical user environment and suite of applications for PDAs and other
 *  devices running Linux. It is included in various embedded Linux distributions
 *  such as OpenZaurus - http://www.aesop-embedded.org
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *
 * Title           : memsetup.S
 * Author          :
 * Created date    : 2005. 06. 26. 23:05:30 KST
 * Description     :
 *
 * $Revision: 1.1.1.1 $
 * $Log: memsetup.S,v $
 * Revision 1.1.1.1  2005/06/27 17:04:30  linuxpark
 * Initial import.
 * 
 * 
 *
 */
#ident  "@(*) $Header: /cvsroot/aesop-embedded/u-boot-aesop/board/aesop2440/memsetup.S,v 1.1.1.1 2005/06/27 17:04:30 linuxpark Exp $"

 

/*
 * Memory Setup stuff - taken from blob memsetup.S
 *
 * Copyright (C) 1999 2000 2001 Erik Mouw (J.A.K.Mouw@its.tudelft.nl) and
 *                     Jan-Derk Bakker (J.D.Bakker@its.tudelft.nl)
 *
 * Modified for the Samsung SMDK2410 by
 * (C) Copyright 2002
 * David Mueller, ELSOFT AG, <d.mueller@elsoft.ch>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */


#include <config.h>
#include <version.h>


/* some parameters for the board */

/*
 *
 * Taken from linux/arch/arm/boot/compressed/head-s3c2410.S
 *
 * Copyright (C) 2002 Samsung Electronics SW.LEE  <hitchcar@sec.samsung.com>
 *
 */

#define BWSCON 0x48000000

/* BWSCON */
#define DW8    (0x0)
#define DW16    (0x1)
#define DW32    (0x2)
#define WAIT    (0x1<<2)
#define UBLB    (0x1<<3)

#define B1_BWSCON    (DW32)
#define B2_BWSCON    (DW16)
#define B3_BWSCON    (DW16 + WAIT + UBLB)
#define B4_BWSCON    (DW16)
#define B5_BWSCON    (DW16)
#define B6_BWSCON    (DW32)
#define B7_BWSCON    (DW32)

/* BANK0CON */
#define B0_Tacs    0x0 /*  0clk */
#define B0_Tcos    0x0 /*  0clk */
#define B0_Tacc    0x7 /* 14clk */
#define B0_Tcoh    0x0 /*  0clk */
#define B0_Tah    0x0 /*  0clk */
#define B0_Tacp    0x0
#define B0_PMC    0x0 /* normal */

/* BANK1CON */
#define B1_Tacs    0x0 /*  0clk */
#define B1_Tcos    0x0 /*  0clk */
#define B1_Tacc    0x7 /* 14clk */
#define B1_Tcoh    0x0 /*  0clk */
#define B1_Tah    0x0 /*  0clk */
#define B1_Tacp    0x0
#define B1_PMC    0x0

#define B2_Tacs    0x0
#define B2_Tcos    0x0
#define B2_Tacc    0x7
#define B2_Tcoh    0x0
#define B2_Tah    0x0
#define B2_Tacp    0x0
#define B2_PMC    0x0

#define B3_Tacs    0x0 /*  0clk */
#define B3_Tcos    0x3 /*  4clk */
#define B3_Tacc    0x7 /* 14clk */
#define B3_Tcoh    0x1 /*  1clk */
#define B3_Tah    0x0 /*  0clk */
#define B3_Tacp    0x3     /*  6clk */
#define B3_PMC    0x0 /* normal */

#define B4_Tacs    0x0 /*  0clk */
#define B4_Tcos    0x0 /*  0clk */
#define B4_Tacc    0x7 /* 14clk */
#define B4_Tcoh    0x0 /*  0clk */
#define B4_Tah    0x0 /*  0clk */
#define B4_Tacp    0x0
#define B4_PMC    0x0 /* normal */

#define B5_Tacs    0x0 /*  0clk */
#define B5_Tcos    0x0 /*  0clk */
#define B5_Tacc    0x7 /* 14clk */
#define B5_Tcoh    0x0 /*  0clk */
#define B5_Tah    0x0 /*  0clk */
#define B5_Tacp    0x0
#define B5_PMC    0x0 /* normal */

#define B6_MT    0x3 /* SDRAM */
#define B6_Trcd     0x1
#define B6_SCAN    0x1 /* 9bit */

#define B7_MT    0x3 /* SDRAM */
#define B7_Trcd    0x1 /* 3clk */
#define B7_SCAN    0x1 /* 9bit */

/* REFRESH parameter */
#define REFEN    0x1 /* Refresh enable */
#define TREFMD    0x0 /* CBR(CAS before RAS)/Auto refresh */
#define Trp    0x0 /* 2clk */
#define Trc    0x3 /* 7clk */
#define Tchr    0x2 /* 3clk */
#define REFCNT    1113 /* period=15.6us, HCLK=60Mhz, (2048+1-15.6*60) */
/**************************************/

_TEXT_BASE:
 .word TEXT_BASE

 

/* S3C2440의 데이터시트를 보면서 코드를 따라 차근차근 그려가며 분석해보면 재미있게 이해할 수 있다. */
//////////////////////////////////////////////////////////////////////////////////////////////
.globl memsetup   // Linker에게 symbol처리 할 수 있도록 export        
memsetup:    // SMRDATA는 아직 메모리가 초기화 되지 않았으므로        
      // flash에서 읽기 위하여 r0에 상대적인 위치를 저장한다.      
 ldr     r0, =SMRDATA // SMRDATA address를 r0레지스터로 이동.
 ldr r1, _TEXT_BASE // _TEXT_BASE에 잇는 data를 r1레지스터로 이동.
 sub r0, r0, r1   // r0에 상대주소값을 저장한다. r0 := r0 - r1
 ldr r1, =BWSCON  /* Bus Width Status Controller의 주소를 r1에 저장 */
 add     r2, r0, #13*4 // 13개의 word레지스터를 r0레지스터와 더한 후 r2레지스터로 이동.
      // 13번 loop를 돌리기 위해 compare할 레지스터 setting(즉, end Address)
0:      // 이곳으로 분기해 염.............................................................................
 ldr     r3, [r0], #4  // r0가 가리키는 address의 data를 r3레지스터로 이동 후 r0값을 4증가시킨다.
 str     r3, [r1], #4  // r1이 가리키는 address에 r3 data를 저장 후 r1값을 4증가시킨다.
 cmp     r2, r0   // r2, r0값을 비교하여 그 결과 값을 CPSR에 setting
 bne     0b    // Z flag가 clear(0)이면 분기해라............................................................
      // set(1)이면 다음 명령어 수행.
                       
 /* everything is fine now */                 
 mov pc, lr   // memsetup함수를 호출한 start.S의 cpu_init_crit으로 복귀한다.      
//////////////////////////////////////////////////////////////////////////////////////////////
 .ltorg
/* the literal pools origin */

SMRDATA:
    .word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
    .word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC))
    .word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC))
    .word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC))
    .word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC))
    .word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC))
    .word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC))
    .word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
    .word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
    .word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
    .word 0x32
    .word 0x30
    .word 0x30

---------------

출처 : http://blog.naver.com/idrukawa/100054113511

u-boot.lds의 ENTRY부분에서 _start로 제어가 넘겨졌었다.

이 _start는 start.S에 선언되어 있다.

 

 

start.S를 보도록 하자.

 

/*
 *      A     EEEE  SSSS   OOO  PPPP
 *     A A    E     S     O   O P   P
 *    AAAAA   EEEE  SSSS  O   O PPPP
 *   A     A  E         S O   O P
 *   A     A  EEEE  SSSS   OOO  P
 *
 *  An Entertainment Solution On a Platform (AESOP) is a completely Open Source
 *  based graphical user environment and suite of applications for PDAs and other
 *  devices running Linux. It is included in various embedded Linux distributions
 *  such as OpenZaurus - http://www.aesop-embedded.org
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *
 * Title           : start.S
 * Author          :
 * Created date    : 2005. 06. 26. 23:20:34 KST
 * Description     :
 *
 * $Revision: 1.1.1.1 $
 * $Log: start.S,v $
 * Revision 1.1.1.1  2005/06/27 17:03:41  linuxpark
 * Initial import.
 * 
 * 
 *
 */
#ident  "@(*) $Header: /cvsroot/aesop-embedded/u-boot-aesop/cpu/arm920t/start.S,v 1.1.1.1 2005/06/27 17:03:41 linuxpark Exp $"


/*
 *  armboot - Startup Code for ARM920 CPU-core
 *
 *  Copyright (c) 2001 Marius Gr?er <mag@sysgo.de>
 *  Copyright (c) 2002 Alex Z?ke <azu@sysgo.de>
 *  Copyright (c) 2002 Gary Jennejohn <gj@denx.de>
 *  Copyright (c) 2005  Junyoung Song <jun0song@kornet.net>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */


#include <config.h>
#include <version.h>


/*
 *************************************************************************
 *
 * Jump vector table as in table 3.1 in [1]
 *
 *************************************************************************
 */


.globl _start
_start: b       reset    /* exception의 처음인 0x00000000번지이다.  이 명령에 의해 reset로 branch한다. reset는 좀 더 아래에 선언되어있다.*/
 ldr pc, _undefined_instruction /* exception vector 설정 */
 ldr pc, _software_interrupt
 ldr pc, _prefetch_abort
 ldr pc, _data_abort
 ldr pc, _not_used
 ldr pc, _irq
 ldr pc, _fiq

/* exception vector의 위치 정의 word(4byte)로 정의한것. */
_undefined_instruction: .word undefined_instruction
_software_interrupt: .word software_interrupt
_prefetch_abort: .word prefetch_abort
_data_abort:  .word data_abort
_not_used:  .word not_used
_irq:   .word irq
_fiq:   .word fiq

 .balignl 16,0xdeadbeef


/*
 *************************************************************************
 *
 * Startup Code (reset vector)
 *
 * do important init only if we don't start from memory!
 * relocate armboot to ram
 * setup stack
 * jump to second stage
 *
 *************************************************************************
 */

_TEXT_BASE:
 .word TEXT_BASE

.globl _armboot_start
_armboot_start:
 .word _start

/*
 * These are defined in the board-specific linker script.
 */
.globl _bss_start
_bss_start:
 .word __bss_start

.globl _bss_end
_bss_end:
 .word _end

#ifdef CONFIG_USE_IRQ
/* IRQ stack memory (calculated at run-time) */
.globl IRQ_STACK_START
IRQ_STACK_START:
 .word 0x0badc0de

/* IRQ stack memory (calculated at run-time) */
.globl FIQ_STACK_START
FIQ_STACK_START:
 .word 0x0badc0de
#endif


/*
 * the actual reset code
 */

 

/*******************************************************
 
* 5가지 동작을 한다. 
  * 1) CPU를 Supervisor mode로 set  2)interrupt를 disable 
  * 3)watchdog을 turn off  4)clock을 setting  5)memory를 setting 
  */
reset:   
 /*                     
  * set the cpu to SVC32 mode
  */
 mrs r0,cpsr
 bic r0,r0,#0x1f // mode bit(하위 5bit)를 클리어 한다.
 orr r0,r0,#0xd3 // interrupt를 disable, supervisor mode로 한다.
 msr cpsr,r0


/* turn off the watchdog */  
#if defined(CONFIG_S3C2400)
# define pWTCON  0x15300000
# define INTMSK  0x14400008 /* Interupt-Controller base addresses */
# define CLKDIVN 0x14800014 /* clock divisor register */

#elif defined(CONFIG_S3C2410) || defined(CONFIG_S3C2440)    /* 만약에 S3C2440이면 아래 정의된 주소로 레지스터가 잡힌다. 자세한 레지스터용도및 주소는 S3C2440의 데이터시트를 참조하세요*/
# define pWTCON  0x53000000
# define INTMSK  0x4A000008 /* Interupt-Controller base addresses */
# define INTSUBMSK 0x4A00001C
# define CLKDIVN 0x4C000014 /* clock divisor register */

#endif

/* 2440이나 2410이면 아래와 같이 watchdog을 turn off하고 클럭을 셋팅한다는 내용이다.  필자의 대상보드는 2440이므로 분석 pass*/
#if defined(CONFIG_S3C2400) || defined(CONFIG_S3C2410)
 ldr     r0, =pWTCON 
 mov     r1, #0x0 
 str     r1, [r0] 

 /*
  * mask all IRQs by setting all bits in the INTMR - default
  */
 mov r1, #0xffffffff

 ldr r0, =INTMSK 
 str r1, [r0]
# if defined(CONFIG_S3C2410) /* 2410일 경우 interrupt submask register를 masking한다. */
 ldr r1, =0x3ff   /* 11bit이므로 */
 ldr r0, =INTSUBMSK
 str r1, [r0]
# endif

 /* FCLK:HCLK:PCLK = 1:2:4 */
 /* default FCLK is 120 MHz ! */
 ldr r0, =CLKDIVN
 mov r1, #3
 str r1, [r0]
#endif /* CONFIG_S3C2400 || CONFIG_S3C2410 */

 


/* 만약 2440이면 아래와 같이 watchdog을 turn off하고 클럭을 셋팅한다. 필자가 사용하는 보드가 나왔다. 분석 들어간다.역시 자세한 사항은 S3C2440의 데이터시트를 참조하길 바란다.*/
#if defined(CONFIG_S3C2440)
 ldr     r0, =pWTCON /* r0로 pWTCON이 들어있는 번지 로딩 */
 mov     r1, #0x0  /* r1에 0을 넣고 */
 str     r1, [r0]   /* r1의 값을 r0가 가리키는 곳의 내용으로 넣는다. */

 /* mask all IRQs by setting all bits in the INTMR - default *//* 부팅시 방해될 수 있는 인터럽트를 마스크한다. */
 mov r1, #0xffffffff
 ldr r0, =INTMSK /* INTMSK가 있는 번지 로딩 */
 str r1, [r0]  /* INTMSK가 있는 번지에 0xffffffff을 넣는다. */
 ldr r1, =0x7fff /* r1에 0x7fff이 있는 번지 로딩 */
 ldr r0, =INTSUBMSK /* r0에 INTSUBMSK가 있는 번지 로딩 */
 str r1, [r0]   /* INTSUBMSK가 있는 번지에 0x7fff를 넣는다. */

 

 /* FCLK:HCLK:PCLK = 1:3:6 */  @ clock setting
 /* default FCLK is 379.2 MHz ! */
 ldr r0, =CLKDIVN     @ CLKDIVN의 주소 0x4C000014
 mov r1, #7      /* #7 = 0b0111, HDIVN = 3, PDIVN = 1
 str r1, [r0]      /* FCLK : HCLK : PCLK = 379.2 : 379.2/3 : 379.2/6

    /* ghcstop add, ==> Clock asynchronous mode */ 
    mrc     p15, 0, r1, c1, c0, 0           /* read ctrl register */
    orr     r1, r1, #0xc0000000            
    mcr     p15, 0, r1, c1, c0, 0           /* write ctrl register */

 
#endif /* CONFIG_S3C2440 */

 

 

 /*
  * we do sys-critical inits only at reboot,
  * not when booting from ram!
  */
#ifdef CONFIG_INIT_CRITICAL
 bl cpu_init_crit     /* cpu_init_crit 서브루틴을 호출한다. cpu_init_crit는 좀 더 아래에 선언되어 있다.*/
#endif


@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
/* memsetup.s 에서 복귀하여 armboot를 ram으로 재배치한다. */         
relocate:    /* relocate U-Boot to RAM     */          
 adr r0, _start  /* r0 <- current position of code   */          
 ldr r1, _TEXT_BASE  /* test if we run from flash or RAM */        
 cmp     r0, r1                  /* don't reloc during debug         */
 beq     stack_setup

 ldr r2, _armboot_start
 ldr r3, _bss_start
 sub r2, r3, r2  /* r2 <- size of armboot            */
 add r2, r0, r2  /* r2 <- source end address         */

copy_loop:
 ldmia r0!, {r3-r10}  /* copy from source address [r0]    */
 stmia r1!, {r3-r10}  /* copy to   target address [r1]    */
 cmp r0, r2   /* until source end addreee [r2]    */
 ble copy_loop

 /* Set up the stack          */
stack_setup:     /* stackpoint를 설정. */
 ldr r0, _TEXT_BASE  /* upper 128 KiB: relocated uboot   */
 sub r0, r0, #CFG_MALLOC_LEN /* malloc area                      */
 sub r0, r0, #CFG_GBL_DATA_SIZE /* bdinfo                        */
#ifdef CONFIG_USE_IRQ
 sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
 sub sp, r0, #12  /* leave 3 words for abort-stack    */

clear_bss:
 ldr r0, _bss_start  /* find start of bss segment        */
 ldr r1, _bss_end  /* stop here                        */
 mov  r2, #0x00000000  /* clear                            */

clbss_l:str r2, [r0]  /* clear loop...                    */
 add r0, r0, #4
 cmp r0, r1
 bne clbss_l

#if 0
 /* try doing this stuff after the relocation */
 ldr     r0, =pWTCON
 mov     r1, #0x0
 str     r1, [r0]

 /*
  * mask all IRQs by setting all bits in the INTMR - default
  */
 mov r1, #0xffffffff
 ldr r0, =INTMR
 str r1, [r0]

 /* FCLK:HCLK:PCLK = 1:2:4 */
 /* default FCLK is 120 MHz ! */
 ldr r0, =CLKDIVN
 mov r1, #3
 str r1, [r0]
 /* END stuff after relocation */
#endif

 ldr pc, _start_armboot    /* Board.c에 포함되어 있는 _start_armboot함수로 branch한다. 실제 위치는 아래 선언된 start_armboot의 위치이다.  여기서 start.s의 동작은 완료되고 이제 RAM에서 남은 부팅절차가 수행된다. */
                       
_start_armboot: .word start_armboot              
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@

 

 

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
/*                      @
 *************************************************************************    @
 *                      @
 * CPU_init_critical registers
 *
 * setup important registers
 * setup memory timing
 *
 *************************************************************************
 */

/* 이 루틴에서 p15는 CP15(coprocessor)를 말하고, c0~c15는 해당 coprocessor의 register를 말하는 것이다. */
/* mcr은 register to coprocessor,  mrc는 coprocessor to register */
 
cpu_init_crit:                    
 /*                     
  * flush v4 I/D caches                 
  */
 mov r0, #0    /* flush : 기억장치 내부의 내용을 지우는 것. 자세한 사항은 S3C2440의 데이터시트를 참조하길 바란다.*/
 mcr p15, 0, r0, c7, c7, 0 /* flush v3/v4 cache */
 mcr p15, 0, r0, c8, c7, 0 /* flush v4 TLB */

 /*
  * disable MMU stuff and caches
  */
 mrc p15, 0, r0, c1, c0, 0
 bic r0, r0, #0x00002300 @ clear bits 13, 9:8 (--V- --RS)
 bic r0, r0, #0x00000087 @ clear bits 7, 2:0 (B--- -CAM)
 orr r0, r0, #0x00000002 @ set bit 2 (A) Align
 orr r0, r0, #0x00001000 @ set bit 12 (I) I-Cache
 mcr p15, 0, r0, c1, c0, 0


 /*
  * before relocating, we have to setup RAM timing
  * because memory timing is board-dependend, you will
  * find a memsetup.S in your board directory.
  */
 mov ip, lr     /* 다시 bl을 이용하므로 lr을 ip레지스터로 이동. */
 bl memsetup   /* memsetup을 호출 -> go to the memsetup.s 여기에서 memsetup.s로 제어가 넘어간다. memsetup.s는 /board/aesop2440/에 위치해있다. memsetup은 다음 포스트에 올리겠다. 넘어가보자. */
 mov lr, ip     /* 서브루틴을 요청햇던 곳으로 이동하기 위해서 ip값을 lr레지스터로 이동. */
 mov pc, lr    /* 서브루틴을 호출한 곳으로 복귀. 위쪽 reset의 마지막 부분이었다. */
 @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@


/*
 *************************************************************************
 *
 * Interrupt handling
 *
 *************************************************************************
 */

@
@ IRQ stack frame.
@
#define S_FRAME_SIZE 72

#define S_OLD_R0 68
#define S_PSR  64
#define S_PC  60
#define S_LR  56
#define S_SP  52

#define S_IP  48
#define S_FP  44
#define S_R10  40
#define S_R9  36
#define S_R8  32
#define S_R7  28
#define S_R6  24
#define S_R5  20
#define S_R4  16
#define S_R3  12
#define S_R2  8
#define S_R1  4
#define S_R0  0

#define MODE_SVC 0x13
#define I_BIT  0x80

/*
 * use bad_save_user_regs for abort/prefetch/undef/swi ...
 * use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
 */

 .macro bad_save_user_regs
 sub sp, sp, #S_FRAME_SIZE
 stmia sp, {r0 - r12}   @ Calling r0-r12
 ldr r2, _armboot_start
 sub r2, r2, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
 sub r2, r2, #(CFG_GBL_DATA_SIZE+8)  @ set base 2 words into abort stack
 ldmia r2, {r2 - r3}   @ get pc, cpsr
 add r0, sp, #S_FRAME_SIZE  @ restore sp_SVC

 add r5, sp, #S_SP
 mov r1, lr
 stmia r5, {r0 - r3}   @ save sp_SVC, lr_SVC, pc, cpsr
 mov r0, sp
 .endm

 .macro irq_save_user_regs
 sub sp, sp, #S_FRAME_SIZE
 stmia sp, {r0 - r12}   @ Calling r0-r12
 add     r8, sp, #S_PC
 stmdb   r8, {sp, lr}^                   @ Calling SP, LR
 str     lr, [r8, #0]                    @ Save calling PC
 mrs     r6, spsr
 str     r6, [r8, #4]                    @ Save CPSR
 str     r0, [r8, #8]                    @ Save OLD_R0
 mov r0, sp
 .endm

 .macro irq_restore_user_regs
 ldmia sp, {r0 - lr}^   @ Calling r0 - lr
 mov r0, r0
 ldr lr, [sp, #S_PC]   @ Get PC
 add sp, sp, #S_FRAME_SIZE
 subs pc, lr, #4   @ return & move spsr_svc into cpsr
 .endm

 .macro get_bad_stack
 ldr r13, _armboot_start  @ setup our mode stack
 sub r13, r13, #(CONFIG_STACKSIZE+CFG_MALLOC_LEN)
 sub r13, r13, #(CFG_GBL_DATA_SIZE+8) @ reserved a couple spots in abort stack

 str lr, [r13]   @ save caller lr / spsr
 mrs lr, spsr
 str     lr, [r13, #4]

 mov r13, #MODE_SVC   @ prepare SVC-Mode
 @ msr spsr_c, r13
 msr spsr, r13
 mov lr, pc
 movs pc, lr
 .endm

 .macro get_irq_stack   @ setup IRQ stack
 ldr sp, IRQ_STACK_START
 .endm

 .macro get_fiq_stack   @ setup FIQ stack
 ldr sp, FIQ_STACK_START
 .endm

/*
 * exception handlers
 */
 .align  5
undefined_instruction:
 get_bad_stack
 bad_save_user_regs
 bl  do_undefined_instruction

 .align 5
software_interrupt:
 get_bad_stack
 bad_save_user_regs
 bl  do_software_interrupt

 .align 5
prefetch_abort:
 get_bad_stack
 bad_save_user_regs
 bl  do_prefetch_abort

 .align 5
data_abort:
 get_bad_stack
 bad_save_user_regs
 bl  do_data_abort

 .align 5
not_used:
 get_bad_stack
 bad_save_user_regs
 bl  do_not_used

#ifdef CONFIG_USE_IRQ

 .align 5
irq:
 get_irq_stack
 irq_save_user_regs
 bl  do_irq
 irq_restore_user_regs

 .align 5
fiq:
 get_fiq_stack
 /* someone ought to write a more effiction fiq_save_user_regs */
 irq_save_user_regs
 bl  do_fiq
 irq_restore_user_regs

#else

 .align 5
irq:
 get_bad_stack
 bad_save_user_regs
 bl  do_irq

 .align 5
fiq:
 get_bad_stack
 bad_save_user_regs
 bl  do_fiq

#endif

 .align 5
.globl reset_cpu
reset_cpu:
#ifdef CONFIG_S3C2400
 bl disable_interrupts
# ifdef CONFIG_TRAB
 bl disable_vfd
# endif
 ldr r1, _rWTCON
 ldr r2, _rWTCNT
 /* Disable watchdog */
 mov r3, #0x0000
 str r3, [r1]
 /* Initialize watchdog timer count register */
 mov r3, #0x0001
 str r3, [r2]
 /* Enable watchdog timer; assert reset at timer timeout */
 mov r3, #0x0021
 str r3, [r1]
_loop_forever:
 b _loop_forever
_rWTCON:
 .word 0x15300000
_rWTCNT:
 .word 0x15300008
#else /* ! CONFIG_S3C2400 */
 mov     ip, #0
 mcr     p15, 0, ip, c7, c7, 0           @ invalidate cache
 mcr     p15, 0, ip, c8, c7, 0           @ flush TLB (v4)
 mrc     p15, 0, ip, c1, c0, 0           @ get ctrl register
 bic     ip, ip, #0x000f                 @ ............wcam
 bic     ip, ip, #0x2100                 @ ..v....s........
 mcr     p15, 0, ip, c1, c0, 0           @ ctrl register
 mov     pc, r0
#endif /* CONFIG_S3C2400 */

---------------

출처 : http://blog.naver.com/idrukawa/100054113199

u-boot코드의 큰 흐름은

1. U-boot.lds에서 ENTRY에 지정된 "_start"함수로 u-boot프로그램이 시작된다.

2. start.s에서 "_start"가 실행되고 "b     reset"에 의해 reset으로 제어가 넘어간다.

3. reset함수에서는

    1) CPU를 supervisor mode로 set시키고

    2) watchdog를 trun off시키고

    3) interrupt를 disable시키고

    4) CPU clock을 셋팅한다.

    5) "cpu_init_crit"에 의해 memsetup.s로 분기되고 메모리를 초기화 한후 start.s로 돌아와

4. armboot를 RAM으로 재배치한다.

5. stackpoint를 설정해 주었으므로 C routine을 실행하기위해 board.c에 포함되어있는 start_armboot()로 branch한다.

6. board.c에서 board에 관련된 모든자원을 초기화하고 main()함수로 이동하게 된다.

 

 

이는 외울 필요없이 코드를 따라가보면 나오는 것이고, 부팅절차를 생각해보면 자연스러운 흐름이다.

 

 

 

그럼 먼저 U-boot.lds를 보도록 하겠다.

 

 

/*
 *      A     EEEE  SSSS   OOO  PPPP
 *     A A    E     S     O   O P   P
 *    AAAAA   EEEE  SSSS  O   O PPPP
 *   A     A  E         S O   O P
 *   A     A  EEEE  SSSS   OOO  P
 *
 *  An Entertainment Solution On a Platform (AESOP) is a completely Open Source
 *  based graphical user environment and suite of applications for PDAs and other
 *  devices running Linux. It is included in various embedded Linux distributions
 *  such as OpenZaurus -
http://www.aesop-embedded.org
 *
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *
 * Title           : u-boot.lds
 * Author          :
 * Created date    : 2005. 06. 26. 23:07:07 KST
 * Description     :
 *
 * $Revision: 1.1.1.1 $
 * $Log: u-boot.lds,v $
 * Revision 1.1.1.1  2005/06/27 17:04:29  linuxpark
 * Initial import.
 * 
 * 
 *
 */

/*
 * (C) Copyright 2002
 * Gary Jennejohn, DENX Software Engineering, <
gj@denx.de>
 *
 * See file CREDITS for list of people who contributed to this
 * project.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of
 * the License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm") 
      /* elf32의  little endian으로 코드를 생성하겠다. */
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)  /* binary를 실행할 수 있는 CPU Architecture로 Arm을 사용하겠다 */
ENTRY(_start)    /* u-boot 프로그램의 시작.  시작되는 함수의 이름은 "_start". 여기에서 _start로 제어가 넘어간다.*/
SECTIONS
{
 . = 0x00000000;

 . = ALIGN(4); /* 프로그램 코드는 0x00000000에서 4byte단위로 정렬된 text section에 놓여질 것이다. */
 .text      :
 {
   cpu/arm920t/start.o (.text)
   *(.text)
 }

 . = ALIGN(4);
 .rodata : { *(.rodata) }

 . = ALIGN(4);
 .data : { *(.data) }

 . = ALIGN(4);
 .got : { *(.got) }

 __u_boot_cmd_start = .;
 .u_boot_cmd : { *(.u_boot_cmd) } //user interface command stucture를 여기에 배치해라.
 __u_boot_cmd_end = .;

 . = ALIGN(4);
 __bss_start = .;  
 .bss : { *(.bss) }  //bss <= global 변수 중에서 0으로 초기화 되지 않은 영역.
 _end = .;
}

 

---------------

출처 : http://blog.naver.com/idrukawa/100054112166

U-Boot는 정말 거대한 프로그램이다.  이런 큰 프로그램은 분석하는 것조차 눈이 빠질 지경이다.  image없이 *.c, *.h, *.o 등등 text파일로만 23Mbyte를 육박한다.  폴더만 110개 가량 파일수는 1300개 이상이다.  이런 거대한 프로그램을 어디서 시작해서 그 함수들은 어떻게 쫓아가면서 분석을 해야할까??  이것역시 큰 고민이고 일이다. 

 

해서 우선은 분석프로그램을 하나 소개할까한다.  이는 멘토인 김남호 수석연구원님이 알려준 분석프로그램으로 source insight라는 프로그램이다.  사용법은 비교적 쉽다.  우선 프로젝트를 생성하여 그 분석하고자 하는 프로그램의 폴더 및 파일을 프로젝트에  추가한다.  필자의 경우 aesop2440보드를 사용할 것이므로 이솝사이트에서 받은 u-boot프로그램을 프로젝트에 추가했다.  그리고 source insight의 오른쪽부분에 검색창에서 분석하고자 하는 파일의 이름을 치면 아래로 목록이 쫙~ 뜬다.  파일을 선택하면 왼쪽의 넓은 창에서 분석을 하면된다.  소스에서 호출된 함수나 정의된 메크로등은 마우스로 클릭하거나 ctrl+더블클릭을 하게되면 선택된 영역과 같은 이름을 갖는 함수정의나 호출부분이 프로젝트전체에서 검색되어져 링크창으로 팝업이되고 쉽게 어떻게 정의된 함수인지 확인할 수 있다.

 

 

p.s> aesop보드용 2440 U-Boot입니다.

            http://www.aesop-embedded.org/sw/u-boot-1.1.2-aesop2440.tar.gz

 

       U-Boot입니다.  각자의 보드에 맞게 수정을 요합니다.

            http://sourceforge.net/projects/u-boot

 

       source insight홈페이지를 링크로 걸겠습니다.

            http://sourceinsight.com

출처 : http://blog.naver.com/idrukawa/100054094629

+ Recent posts