* Startup Code for MIPS32 XBURST CPU-core
*
* Copyright (c) 2010 Xiangfu Liu <xiangfu@sharism.cc>
*
* 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>
#include <asm/regdef.h>
#include <asm/mipsregs.h>
#include <asm/addrspace.h>
#include <asm/cacheops.h>
#include <asm/arch/base.h>
#include "traps.h"
.set noreorder
.set mips32r2
.globl _start
.text
_start:
#if (defined(CONFIG_X2000_V12) || defined(CONFIG_M300))
#ifdef CONFIG_JZ_SECURE_SUPPORT
.space 2048, 0
#endif
#endif
/*串口发送数据 0*/
#ifdef _DEBUG
la v0, 0xb0030000
li t0, '0'
sw t0, 0(v0)
loop0:
lbu v1, 0x14(v0)
li t1, 0x60
andi v1, v1, 0x60
bne v1, t1, loop0
nop
nop
#endif
/* Initialize $gp */
bal 1f
nop
.word _gp
1:
lw gp, 0(ra)
/*串口发送数据 1*/
#ifdef _DEBUG
la v0, 0xb0030000
li t0, '1'
sw t0, 0(v0)
loop1:
lbu v1, 0x14(v0)
andi v1, v1, 0x60
bne v1, 0x60, loop1
nop
nop
#endif
/* Set up temporary stack 4M*/
li sp, CONFIG_SYS_SDRAM_BASE + CONFIG_SYS_INIT_SP_OFFSET
/*串口发送数据 2*/
#ifdef _DEBUG
la v0, 0xb0030000
li t0, '2'
sw t0, 0(v0)
loop2:
lbu v1, 0x14(v0)
andi v1, v1, 0x60
bne v1, 0x60, loop2
nop
nop
#endif
la t9, board_init_f
/*串口发送数据 4*/
#ifdef _DEBUG
la v0, 0xb0030000
li t0, '3'
sw t0, 0(v0)
loop3:
lbu v1, 0x14(v0)
andi v1, v1, 0x60
bne v1, 0x60, loop3
nop
nop
#endif
jr t9
nop
/*重定向是把uboot代码从CONFIG_SYS_MONITOR_BASE=0X80100000地址搬运到addr_moni=0x87f5c000地址运行,搬运后,每个程序相对偏移一样,等于relocate_offset
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
* a0 = addr_sp #0x86f1bf48
* a1 = gd #global_data
* a2 = destination address #0x87f5c000
*/
.globl relocate_code
.ent relocate_code
relocate_code:
move sp, a0 # set new stack pointer sp=a0=0x86f1bf48
li t0, CONFIG_SYS_MONITOR_BASE = t0 = 0x80100000
sub t6, a2, t0 # t6 <-- relocation offset = 0x87f5c000 - 0x80100000 = 0x7e5c000
la t3, in_ram #加载in_ram标号地址
lw t2, -12(t3) #in_ram向前偏移12个字节 # t2 <-- __image_copy_end
move t1, a2 #t1 = a2 = 0x87f5c000
add gp, t6 #gp = gp + 0x7e5c000 # adjust gp
/*
* t0 = source address = 0x80100000
* t1 = target address = 0x87f5c000
* t2 = source end address = __image_copy_end
*/
#搬运代码
1:
lw t3, 0(t0)
sw t3, 0(t1)
addu t0, 4
blt t0, t2, 1b
addu t1, 4
/* If caches were enabled, we would have to flush them here. */
/* flush d-cache */
i t0, KSEG0 #0x80000000
or t1, t0, CONFIG_SYS_DCACHE_SIZE #0x80008000
2:
cache INDEX_WRITEBACK_INV_D, 0(t0)
bne t0, t1, 2b
addi t0, CONFIG_SYS_CACHELINE_SIZE #32
sync
/* flush i-cache */
li t0, KSEG0
or t1, t0, CONFIG_SYS_ICACHE_SIZE
3:
cache INDEX_INVALIDATE_I, 0(t0)
bne t0, t1, 3b
addi t0, CONFIG_SYS_CACHELINE_SIZE
/* Invalidate BTB */
mfc0 t0, CP0_CONFIG, 7
nop
ori t0, 2
mtc0 t0, CP0_CONFIG, 7
nop
/* Jump to where we've relocated ourselves */
addi t0, a2, in_ram - _start #t0 = a2 + (in_ram - _start)=0x87f5c00(重定向后的ram起始地址) + (in_ram - _start)(此时的in_ram相对于_start=CONFIG_SYS_MONITOR_BASE的相对偏移)
#获取重定向后的in_ram
jr t0
nop
.word __rel_dyn_end
.word __rel_dyn_start
.word __image_copy_end
.word _GLOBAL_OFFSET_TABLE_
.word num_got_entries
in_ram:
/*
* Now we want to update GOT.
*
* GOT[0] is reserved. GOT[1] is also reserved for the dynamic object
* generated by GNU ld. Skip these reserved entries from relocation.
*/
lw t3, -4(t0)#800ffffc # t3 <-- num_got_entries #t0 = CONFIG_SYS_MONITOR_BASE 0x80100000
lw t4, -8(t0)#800ffff8 # t4 <-- _GLOBAL_OFFSET_TABLE_ #t4获取到旧的got地址
add t4, t6 # t4 now holds relocated _G_O_T_ #t6 = a2 - t0 = 0x87f5c000 - 0x80100000 t4+relocate_offset = 重定位之后的got表地址
addi t4, t4, 8 # skipping first two entries
li t2, 2
1:
lw t1, 0(t4) #将got表中每一个entry存储的全局变量的地址 加载到 t1中
beqz t1, 2f #如果entry中存储的地址为zero,跳转到label 2执行
add t1, t6 #分支延时槽: 将label中存储的全局变量的地址加上relocate_offset
sw t1, 0(t4) #将计算后的全局变量的地址存放到got的entry项中
2:
addi t2, 1 #处理完一个got entry后t2计数加1
blt t2, t3, 1b #比较当前处理过的got-entry数是不是已经到达got中总entry数num_got_entries,如果没有则跳转到label 1,重新处理下一个entry
addi t4, 4 #在分支延时槽中将got-pointer + 4,指向下一个entry地址
/* Update dynamic relocations */
lw t1, -16(t0) # t1 <-- __rel_dyn_start
lw t2, -20(t0) # t2 <-- __rel_dyn_end
b 2f # skip first reserved entry
addi t1, 8
#rel.dyn段加上-pie就会自动出现,目的是告诉我们那些是位置无关代码需要重定位,每一个rel.dyn是8个字节,高四位是label低四位存储的是no-pic地址的地址
1:
lw t3, -4(t1) # t3 <-- relocation info,获取高位label
sub t3, 3 #如果高位label值等于3,就处理,否则,直接获下一个rel.dyn,
bnez t3, 2f # skip non R_MIPS_REL32 entries
nop
lw t3, -8(t1) # t3 <-- location to fix up in FLASH 加载该rel.dyn存储着低四位的程序地址(重定位之前在flash中的地址)的地址
lw t4, 0(t3) # t4 <-- original pointer从改地址中获取到程序的地址
add t4, t6 # t4 <-- adjusted pointer给程序地址加上relocate_offset,得到重定位后的程序运行地址(在ram中的地址)
add t3, t6 # t3 <-- location to fix up in RAM将存放程序地址的地址改为在ram中的地址
sw t4, 0(t3) #保存重定向后程序地址
2:
blt t1, t2, 1b #处理所有rel.dyn
addi t1, 8 # each rel.dyn entry is 8 bytes
/*
* Clear BSS #将bss全部写0
*
* GOT is now relocated. Thus __bss_start and __bss_end can be
* accessed directly via $gp.
*/
la t1, __bss_start # t1 <-- __bss_start
la t2, __bss_end # t2 <-- __bss_end
1:
sw zero, 0(t1)
blt t1, t2, 1b
addi t1, 4
#board_init_r(gd,addr_moni)-->r(ram)
#board_init_r有两个参数,参数1:global_data 参数2:重定向后运行地址addr_moni = 0x87f5c000(根据x2000nand打印信息获取)
move a0, a1 # a0 <-- gd
la t9, board_init_r
jr t9
move a1, a2 #分支延时槽
.end relocate_code
#ifdef CONFIG_XBURST_TRAPS
// push context: at, v0-v1,a0-a3,t0-t9,s0-s7,fp,ra, & pc
.macro SAVE_ALL
.set noat
.set noreorder
sw ra,PT_RA(sp)
sw fp,PT_FP(sp)
sw t9,PT_T9(sp)
sw t8,PT_T8(sp)
sw s7,PT_S7(sp)
sw s6,PT_S6(sp)
sw s5,PT_S5(sp)
sw s4,PT_S4(sp)
sw s3,PT_S3(sp)
sw s2,PT_S2(sp)
sw s1,PT_S1(sp)
sw s0,PT_S0(sp)
sw t7,PT_T7(sp)
sw t6,PT_T6(sp)
sw t5,PT_T5(sp)
sw t4,PT_T4(sp)
sw t3,PT_T3(sp)
sw t2,PT_T2(sp)
sw t1,PT_T1(sp)
sw t0,PT_T0(sp)
sw a3,PT_A3(sp)
sw a2,PT_A2(sp)
sw a1,PT_A1(sp)
sw a0,PT_A0(sp)
sw v1,PT_V1(sp)
sw v0,PT_V0(sp)
sw AT,PT_AT(sp)
mfc0 k1,CP0_STATUS
sw k1,PT_STATUS(sp)
mfc0 k1, CP0_EPC
sw k1,PT_EPC(sp)
mflo k1
sw k1,PT_LO(sp)
mfhi k1
sw k1,PT_HI(sp)
nop
la t1,0x80000004
sw sp,0(t1)
.endm
#define NESTED(symbol, framesize, rpc) \
.globl symbol; \
.align 2; \
.type symbol, @function; \
.ent symbol, 0; \
symbol: .frame sp, framesize, rpc
/*
* END - mark end of function
*/
#define END(function) \
.end function; \
.size function, .-function
/*
* General exception vector for all other CPUs.
*
* Be careful when changing this, it has to be at most 128 bytes
* to fit into space reserved for the exception handler.
*/
NESTED(handle_exception, 0, sp)
addi sp,sp,-PT_LEN
SAVE_ALL
la t9,0x80000000
lw t9,0(t9)
jr t9
nop
nop
END(handle_exception)
#endif