虽然,分析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_BASECFG_UBOOT_BASE
#endif
#endif
上面这些宏的定义都在Smdk6410.h (include\configs)文件中,如下所示:
/* base address for uboot */
#ifdef CONFIG_ENABLE_MMU
#define CFG_UBOOT_BASE0xc7e00000
#else
#define CFG_UBOOT_BASE0x57e00000
#endif
#define CFG_PHY_UBOOT_BASEMEMORY_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: breset
ldrpc, _undefined_instruction
ldrpc, _software_interrupt
ldrpc, _prefetch_abort
ldrpc, _data_abort
ldrpc, _not_used
ldrpc, _irq
ldrpc, _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
*/
.align5
undefined_instruction:
get_bad_stack
bad_save_user_regs
bldo_undefined_instruction
.align5
software_interrupt:
get_bad_stack_swi
bad_save_user_regs
bldo_software_interrupt
.align5
prefetch_abort:
get_bad_stack
bad_save_user_regs
bldo_prefetch_abort
.align5
data_abort:
get_bad_stack
bad_save_user_regs
bldo_data_abort
.align5
not_used:
get_bad_stack
bad_save_user_regs
bldo_not_used
#ifdef CONFIG_USE_IRQ 我们没有定义:#undef CONFIG_USE_IRQ/* we don't need IRQ/FIQ stuff */
.align5
irq:
get_irq_stack
irq_save_user_regs
bldo_irq
irq_restore_user_regs
.align5
fiq:
get_fiq_stack
/* someone ought to write a more effiction fiq_save_user_regs */
irq_save_user_regs
bldo_fiq
irq_restore_user_regs
#else 我们使用这一部分
.align5
irq:
get_bad_stack
bad_save_user_regs
bldo_irq
.align5
fiq:
get_bad_stack
bad_save_user_regs
bldo_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
@ msrspsr_c, r13
msrspsr, 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这两个指令了,不过我在另外一篇我转载的博客中有很好的从实例中分析了这两个指令的用法。一看就能明了。
.macrobad_save_user_regs
subsp, sp, #S_FRAME_SIZE@ carve out a frame on current user stack
其中有定义:#define S_FRAME_SIZE72
stmiasp, {r0 - r12}@ Save user registers (now in svc mode) r0-r12
ldrr2, _armboot_start
subr2, r2, #(CFG_MALLOC_LEN)
subr2, r2, #(CFG_GBL_DATA_SIZE+8)@ set base 2 words into abort stack
ldmiar2, {r2 - r3}@ get values for "aborted" pc and cpsr (into parm regs)
addr0, sp, #S_FRAME_SIZE@ grab pointer to old stack
addr5, sp, #S_SP
movr1, lr
stmiar5, {r0 - r3}@ save sp_SVC, lr_SVC, pc, cpsr
movr0, sp@ save current stack into r0 (param register)
.endm
其实这个宏的主要作用就是保存下面这些寄存器的内容,如下所示:
#define S_OLD_R068
#define S_PSR64
#define S_PC60
#define S_LR56
#define S_SP52
#define S_IP48
#define S_FP44
#define S_R1040
#define S_R936
#define S_R832
#define S_R728
#define S_R624
#define S_R520
#define S_R416
#define S_R312
#define S_R28
#define S_R14
#define S_R00
.macroirq_save_user_regs 和上面的作用差不多
subsp, sp, #S_FRAME_SIZE
stmiasp, {r0 - r12}@ Calling r0-r12
addr8, sp, #S_PC@ !!!! R8 NEEDS to be saved !!!! a reserved stack spot would be good.
stmdbr8, {sp, lr}^@ Calling SP, LR
strlr, [r8, #0]@ Save calling PC
mrsr6, spsr
strr6, [r8, #4]@ Save CPSR
strr0, [r8, #8]@ Save OLD_R0
movr0, 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*/
}
---------------------------------------------------------------
好了这篇就说到这里了,下篇继续。