三星uboot1.1.6源码分析——start.s(1)
虽然,分析start.s的文件在网上已经很多,但还是在这里对自己的分析做个记录,方便以后查看。
现在开始:
#include <config.h>
#include <version.h>
#ifdef CONFIG_ENABLE_MMU
#include <asm/proc/domain.h>
#endif
#include <regs.h>
#ifndef CONFIG_ENABLE_MMU 我们定义了#define CONFIG_ENABLE_MMU,所以这些用不到
#ifndef CFG_PHY_UBOOT_BASE
#define CFG_PHY_UBOOT_BASE CFG_UBOOT_BASE
#endif
#endif
上面这些宏的定义都在Smdk6410.h (include\configs)文件中,如下所示:
/* base address for uboot */
#ifdef CONFIG_ENABLE_MMU
#define CFG_UBOOT_BASE 0xc7e00000
#else
#define CFG_UBOOT_BASE 0x57e00000
#endif
#define CFG_PHY_UBOOT_BASE MEMORY_BASE_ADDRESS + 0x7e00000
#define MEMORY_BASE_ADDRESS0x50000000
所以上面的CFG_PHY_UBOOT_BASE为0x57e00000
CFG_UBOOT_BASE为0xc7e00000
/*
*************************************************************************
*
* Jump vector table as in table 3.1 in [1]
*
*************************************************************************
*/
.globl _start 在链接文件有如下内容:
---------------------------
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
/*OUTPUT_FORMAT("elf32-arm", "elf32-arm", "elf32-arm")*/
OUTPUT_ARCH(arm)
ENTRY(_start)
SECTIONS
{
. = 0x00000000;
. = ALIGN(4);
.text :
{
cpu/s3c64xx/start.o(.text)
---------------------------
_start: b reset
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
_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
_pad:
.word 0x12345678 /* now 16*4=64 */
.global _end_vect
_end_vect:
.balignl 16,0xdeadbeef
/*
--------------------------------------------------------------------------
上面这些就都不说了,网上有很多这上面的资料,讲的都很详细,忘记了再查。不过这些undefined_instruction、data_abort等在本文件的后面都有定义,我在前面把他们粘贴在下面,方便查看,如下所示:
/*
* exception handlers
*/
.align 5
undefined_instruction:
get_bad_stack
bad_save_user_regs
bl do_undefined_instruction
.align 5
software_interrupt:
get_bad_stack_swi
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 我们没有定义:#undef CONFIG_USE_IRQ/* we don't need IRQ/FIQ stuff */
.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
--------------------------------------------
1、其中get_bad_stack也在同一个文件中,如下所示:
.macro get_bad_stack
ldrr13, _armboot_start@ setup our mode stack (enter in banked mode)
其中有如下定义:
.globl _armboot_start
_armboot_start:
.word _start
subr13, r13, #(CFG_MALLOC_LEN)@ move past malloc pool
subr13, r13, #(CFG_GBL_DATA_SIZE+8) @ move to reserved a couple spots for abort stack
strlr, [r13]@ save caller lr in position 0 of saved stack
mrslr, spsr@ get the spsr
strlr, [r13, #4]@ save spsr in position 1 of saved stack
movr13, #MODE_SVC@ prepare SVC-Mode
@ msr spsr_c, r13
msr spsr, r13@ switch modes, make sure moves will execute
movlr, pc@ capture return pc
movspc, lr@ jump to next instruction & switch modes.
.endm
这个宏的功能应该是得到对应异常的堆栈指针。
2、其中bad_save_user_regs也在同一个文件中,如下所示:
/*
* use bad_save_user_regs for abort/prefetch/undef/swi ...
* use irq_save_user_regs / irq_restore_user_regs for IRQ/FIQ handling
*/
下面这一段汇编代码还是很好理解的,最困难的可能就是stmia和ldmia这两个指令了,不过我在另外一篇我转载的博客中有很好的从实例中分析了这两个指令的用法。一看就能明了。
.macro bad_save_user_regs
sub sp, sp, #S_FRAME_SIZE@ carve out a frame on current user stack
其中有定义:#define S_FRAME_SIZE72
stmia sp, {r0 - r12}@ Save user registers (now in svc mode) r0-r12
ldr r2, _armboot_start
sub r2, r2, #(CFG_MALLOC_LEN)
sub r2, r2, #(CFG_GBL_DATA_SIZE+8)@ set base 2 words into abort stack
ldmia r2, {r2 - r3}@ get values for "aborted" pc and cpsr (into parm regs)
add r0, sp, #S_FRAME_SIZE@ grab pointer to old stack
add r5, sp, #S_SP
mov r1, lr
stmia r5, {r0 - r3}@ save sp_SVC, lr_SVC, pc, cpsr
mov r0, sp@ save current stack into r0 (param register)
.endm
其实这个宏的主要作用就是保存下面这些寄存器的内容,如下所示:
#define S_OLD_R068
#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
.macro irq_save_user_regs 和上面的作用差不多
sub sp, sp, #S_FRAME_SIZE
stmia sp, {r0 - r12}@ Calling r0-r12
add r8, sp, #S_PC@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
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
3、
再来说说do_software_interrupt、do_data_abort等等类似与这些又在那里定义的呢?
它们都定义在:Interrupts.c (cpu\s3c64xx)文件中,如下所示:
void do_undefined_instruction(struct pt_regs *pt_regs)
{
printf("undefined instruction\n");
show_regs(pt_regs);
bad_mode();
}
void do_software_interrupt(struct pt_regs *pt_regs)
{
printf("software interrupt\n");
show_regs(pt_regs);
bad_mode();
}
void do_prefetch_abort(struct pt_regs *pt_regs)
{
printf("prefetch abort\n");
show_regs(pt_regs);
bad_mode();
}
void do_data_abort(struct pt_regs *pt_regs)
{
printf("data abort\n");
show_regs(pt_regs);
bad_mode();
}
void do_not_used(struct pt_regs *pt_regs)
{
printf("not used\n");
show_regs(pt_regs);
bad_mode();
}
void do_fiq(struct pt_regs *pt_regs)
{
printf("fast interrupt request\n");
show_regs(pt_regs);
bad_mode();
}
void do_irq(struct pt_regs *pt_regs)
{
printf("interrupt request\n");
show_regs(pt_regs);
bad_mode();
}
-------------------------------------------
其中又有
void bad_mode(void)
{
panic("Resetting CPU ...\n");
reset_cpu(0);
}
/* * reset the cpu by setting up the watchdog timer and let him time out */
void reset_cpu(ulong ignored)
{
printf("reset... \n\n\n");
#if defined(CONFIG_S3C6400)
SW_RST_REG = 0x6400;
#elif defined(CONFIG_S3C6410)
SW_RST_REG = 0x6410;
#elif defined(CONFIG_S3C6430)
SW_RST_REG = 0x6410;
#endif
/* loop forever and wait for reset to happen */
while (1)
{
if (serial_tstc())
{
serial_getc();
break;
}
}
/*NOTREACHED*/
}
---------------------------
好了这篇就说到这里了,下篇继续。