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

+ Recent posts