下面爲初始化CPU的代碼,實現的功能依次爲屏蔽watchdog、初始化中斷控制寄存器、清空Cache、關閉MMU等。
.globl init_e300_core
init_e300_core: /* time t 10 */
/* Initialize machine status; enable machine check interrupt */
li r3, MSR_KERNEL /*設置MSR,允許數據\指令複製以及Machine check*/
rlwimi r3, r5, 0, 25, 25 /* preserve IP bit set by HRCW */
#ifdef DEBUG
rlwimi r3, r5, 0, 21, 22 /* debugger might set SE & BE bits */
#endif
SYNC /* Some chip revs need this... */
mtmsr r3
SYNC
mtspr SRR1, r3 /* Make SRR1 match MSR 中斷相關*/
lis r3, CFG_IMMR@h
#if defined(CONFIG_WATCHDOG)
/* Initialise the Wathcdog values and reset it (if req) */
lis r4, CFG_WATCHDOG_VALUE
ori r4, r4, (SWCRR_SWEN | SWCRR_SWRI | SWCRR_SWPR)
stw r4, SWCRR(r3)
/* and reset it */
li r4, 0x556C
sth r4, SWSRR@l(r3)
li r4, -0x55C7
sth r4, SWSRR@l(r3)
#else
/* 關閉Wathcdog */
lwz r4, SWCRR(r3)
/* Check to see if its enabled for disabling
once disabled by SW you can't re-enable */
andi. r4, r4, 0x4
beq 1f
xor r4, r4, r4
stw r4, SWCRR(r3)
1:
#endif /* CONFIG_WATCHDOG */
/* Initialize the Hardware Implementation-dependent Registers */
/* HID0 also contains cache control */
/*------------------------------------------------------*/
lis r3, CFG_HID0_INIT@h
ori r3, r3, CFG_HID0_INIT@l
SYNC
mtspr HID0, r3
lis r3, CFG_HID0_FINAL@h
ori r3, r3, CFG_HID0_FINAL@l
SYNC
mtspr HID0, r3
lis r3, CFG_HID2@h
ori r3, r3, CFG_HID2@l
SYNC
mtspr HID2, r3
/* 關閉MMU功能,先清空所有BAT (塊地址轉換)*/
xor r0, r0, r0
mtspr DBAT0U, r0
mtspr DBAT0L, r0
mtspr DBAT1U, r0
mtspr DBAT1L, r0
mtspr DBAT2U, r0
mtspr DBAT2L, r0
mtspr DBAT3U, r0
mtspr DBAT3L, r0
mtspr IBAT0U, r0
mtspr IBAT0L, r0
mtspr IBAT1U, r0
mtspr IBAT1L, r0
mtspr IBAT2U, r0
mtspr IBAT2L, r0
mtspr IBAT3U, r0
mtspr IBAT3L, r0
SYNC
/* 禁用tlb(快表) */
li r3, 32
mtctr r3
li r3, 0
1: tlbie r3
addi r3, r3, 0x1000
bdnz 1b
SYNC
/* Done! */
Blr
這裏需要注意的是,當程序在Flash中運行時,執行程序跳轉時使用了跳轉指令,但是不是使用絕對地址的跳轉(即直接對PC操作)。因爲若使用絕對地址,那麼程序的取址就是相對於當前PC位置向前或向後的一段空間,而不會跳進SDRAM中。
4、初始化內存控制器
PowerPC處理器初識化內存控制器就是通過操作BAT以及TLB來實現的,將IBAT0~7以及DBAT0~7初始化,並禁用TLB,代碼如下:
/* setup_bats - set them up to some initial state */
.globl setup_bats
setup_bats:
addis r0, r0, 0x0000
/* IBAT 0 */
addis r4, r0, CFG_IBAT0L@h
ori r4, r4, CFG_IBAT0L@l
addis r3, r0, CFG_IBAT0U@h
ori r3, r3, CFG_IBAT0U@l
mtspr IBAT0L, r4
mtspr IBAT0U, r3
isync
/* DBAT 0 */
addis r4, r0, CFG_DBAT0L@h
ori r4, r4, CFG_DBAT0L@l
addis r3, r0, CFG_DBAT0U@h
ori r3, r3, CFG_DBAT0U@l
mtspr DBAT0L, r4
mtspr DBAT0U, r3
isync
#ifdef CONFIG_HIGH_BATS
/* IBAT 4 */
addis r4, r0, CFG_IBAT4L@h
ori r4, r4, CFG_IBAT4L@l
addis r3, r0, CFG_IBAT4U@h
ori r3, r3, CFG_IBAT4U@l
mtspr IBAT4L, r4
mtspr IBAT4U, r3
isync
/* DBAT 4 */
addis r4, r0, CFG_DBAT4L@h
ori r4, r4, CFG_DBAT4L@l
addis r3, r0, CFG_DBAT4U@h
ori r3, r3, CFG_DBAT4U@l
mtspr DBAT4L, r4
mtspr DBAT4U, r3
isync
#endif
/* Invalidate TLBs.
* -> for (val = 0; val < 0x20000; val+=0x1000)
* -> tlbie(val);
*/
lis r3, 0
lis r5, 2
1:
tlbie r3
addi r3, r3, 0x1000
cmp 0, 0, r3, r5
blt 1b
blr
上面只貼出了高低位各一個BAT的操作代碼,其他的類似。
5、複製程序到RAM
PowerPC中此段程序並不返回,在將程序代碼全部複製到ROM中後,將會直接繼續在RAM中運行:
/*完成了代碼複製,不返回,直接調用in_ram執行*/
addi r0, r10, in_ram - _start + EXC_OFF_SYS_RESET
mtlr r0
blr
.globl relocate_code
relocate_code:
mr r1, r3 /* 創建一個新的棧指針 */
mr r9, r4 /* 備份 */
mr r10, r5
mr r3, r5 /* r3:拷貝的終點 */
lis r4, CFG_MONITOR_BASE@h /* r4:拷貝的起點 */
ori r4, r4, CFG_MONITOR_BASE@l
lwz r5, GOT(__init_end)
sub r5, r5, r4 /* r5:拷貝的長度 */
li r6, CFG_CACHELINE_SIZE /* Cache Line Size */
/* New GOT-PTR = (old GOT-PTR - CFG_MONITOR_BASE) + Destination Address */
sub r15, r10, r4
/* First our own GOT */
add r14, r14, r15
/* then the one used by the C code */
add r30, r30, r15
/* Now relocate code */
cmplw cr1,r3,r4
addi r0,r5,3
srwi. r0,r0,2
beq cr1,4f /* In place copy is not necessary */
beq 7f /* Protect against 0 count */
mtctr r0
bge cr1,2f
la r8,-4(r4)
la r7,-4(r3)
/* copy */
1: lwzu r0,4(r8)
stwu r0,4(r7)
bdnz 1b
addi r0,r5,3
srwi. r0,r0,2
mtctr r0
la r8,-4(r4)
la r7,-4(r3)
/* and compare */
20: lwzu r20,4(r8)
lwzu r21,4(r7)
xor. r22, r20, r21
bne 30f
bdnz 20b
b 4f
/* compare failed */
30: li r3, 0
blr
2: slwi r0,r0,2 /* re copy in reverse order ... y do we needed it? */
add r8,r4,r0
add r7,r3,r0
3: lwzu r0,-4(r8)
stwu r0,-4(r7)
bdnz 3b
/*
* Now flush the cache: note that we must start from a cache aligned
* address. Otherwise we might miss one cache line.
*/
4: cmpwi r6,0
add r5,r3,r5
beq 7f /* Always flush prefetch queue in any case */
subi r0,r6,1
andc r3,r3,r0
mr r4,r3
5: dcbst 0,r4
add r4,r4,r6
cmplw r4,r5
blt 5b
sync /* Wait for all dcbst to complete on bus */
mr r4,r3
6: icbi 0,r4
add r4,r4,r6
cmplw r4,r5
blt 6b
7: sync /* Wait for all icbi to complete on bus */
isync
6、初始化堆棧
對於mpc83xx系列,初始化堆棧代碼如下:
/* set up the stack pointer in our newly created cache-ram (r1) */
lis r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@h
ori r1, r1, (CFG_INIT_RAM_ADDR + CFG_GBL_DATA_OFFSET)@l
li r0, 0 /* Make room for stack frame header and */
stwu r0, -4(r1) /* clear final stack frame so that */
stwu r0, -4(r1) /* stack backtraces terminate cleanly */
7、跳轉到Stage2入口處
這也是Stage1的最後一步,程序在執行到這一步後,基本的硬件初始化工作也就完成了,下面是跳轉的代碼:
GET_GOT /* initialize GOT access */
/* r3: IMMR */
lis r3, CFG_IMMR@h
/* run low-level CPU init code (in Flash)*/
bl cpu_init_f
/* r3: BOOTFLAG */
mr r3, r21
/* run 1st part of board init code (in Flash)*/
bl board_init_f
其中board_init_f就是Stage2的函數入口。
由上可以看出start.S的流程爲:異常向量——上電覆位後進入復位異常向量——跳到啓動代碼處——設置處理器進入管理模式——關閉看門狗——關閉中斷——設置時鐘分頻——關閉MMU和CACHE——進入lowlever_init.S——檢查當前代碼所處的位置,如果在FLASH中就將代碼搬移到RAM中。至此,Stage1分析到此結束。
跳轉到board_init_f後,程序開始執行Stage2階段,代碼多爲C。