U-boot源代碼全分析系列(基於PowerPC)-2

3、初始化CPU相關

    下面爲初始化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。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章