MPC860上電初始化流程分析
作者: 村姑
【復位向量】
860復位后,執(zhí)行的第一條指令位于4GB地址空間的什么地方?
對于PowerPC,復位也是一種異常(你可以理解為CPU自己產(chǎn)生的中斷),向量號為0x100。異常向量表的基地址加上復位向量號即為復位向量,也就是CPU開始執(zhí)行指令的地方。異常向量表在內存空間的可能位置有2個:0x00000000和0xFFF00000。具體是哪一個由MSR寄存器的IP位指定:若IP位為0,則異常向量表在0x0處,否則在0xFFF00000處。860有多種復位方式,對于hard reset,MSR的IP位由硬件配置字的IIP(Initial Interrupt Prefix)位決定。
所以PowerPC的復位向量為0x100或者0xFFF00100。以下我們假定0xFFF00100。
【硬件配置字】
TBD
【Flash Memory】
假設有128K字節(jié)的Flash,并打算把它映射到CPU內存空間的0xFE000000開始的地方。但由于復位向量為0xFFF00100,那么怎么才能讓CPU從Flash中偏移0x100的地方開始執(zhí)行指令呢?
860內嵌的memory controller有個引腳,#CS0,稱為global boot chip select,一般把它連接到Flash或EPROM的片選上。假定這128K Flash是8位數(shù)據(jù)寬度,地址線A16..0分別連接到860的A15..A31(注意A31為860地址線的最低位),數(shù)據(jù)線D0..7分別和860的D0..7相連。再看控制#CS0的BR0和OR0寄存器,CPU復位后,BR0.V=1(Valid)且BR0.BA[0..16]=0,OR0.AM[0..16]=0。由于地址掩碼AM位全為0,意味內存控制器會忽略所有參與片選邏輯的地址線A0..A16,所以產(chǎn)生的#CS0總是有效的。這樣,上電后Flash總會被選中。CPU從Flash偏移0x100的地方取指令。這個結果和復位向量表基地址,以及以后Flash映射到CPU內存空間的什么位置都是無關的。
以上結果還有一個現(xiàn)象,就是復位后,CPU的4GB內存空間內都是Flash。4GB空間的每個128K的塊都被映射到Flash。原因用一句話概括:Flash只使用了32位地址線的低17根,且缺省地被選中。
【VxWorks初始化】
/* romInit.s - Motorola 860mbx ROM initialization module */
/* Copyright 1984-1998 Wind River Systems, Inc. */
/* Copyright 1997,1998 Motorola, Inc. All Rights Reserved */
.data
■ 定義數(shù)據(jù)段。
.globl copyright_wind_river
.long copyright_wind_river
■ 申明(declare)全局變量_copyright_wind_river并使用它定義一個新變量。
■ 注意”.globl”是申明而非定義。”_copyright_wind_river”變量在Tornado的庫(對于MPC860,為[Tornado]/target/lib/libPPC860gnuvx.a)中的一個模塊copyright.o中定義。
■ ”.long”定義一個32-bit的全局變量(沒有變量名),變量的初始值為_copyright_wind_river的值(還是地址?)。由于在Makefile中規(guī)定了romInit.o為第一個鏈接的模塊,所以這個無名變量將出現(xiàn)在數(shù)據(jù)段的最開始。
■ 不清楚_copyright_wind_river的用途,以及這個無名變量的用途。
#define _ASMLANGUAGE
■ 定義_ASMLANGUAGE。GNU匯編器GAS看到這個定義后,會按照C的語法進行預處理,所以GAS預處理器能夠認識C頭文件中定義的類型和宏(?)。如果不定義_ASMLANGUAGE,以下的#include語句將無法編譯。
#include "vxWorks.h"
#include "asm.h"
#include "cacheLib.h"
#include "config.h"
#include "regs.h"
#include "sysLib.h"
#include "drv/multi/ppc860Siu.h"
.globl _romInit
.globl romInit
.extern romStart
.extern mbxI2cConfigParamsGet
.extern mbxI2cMemcConfig
.text
.align 2
/******************************************************************************
* romInit - entry point for VxWorks in ROM
*/
_romInit:
romInit:
■ 同時定義_romInit和romInit的原因是,有些編譯器產(chǎn)生的對外部符號的調用不加下劃線,而有些加。
bl cold
bl start
■ 若是熱啟動,則跳轉到start。激活熱啟動的代碼將跳轉到romInit+4處。注意PowerPC的所有指令都占4字節(jié)(32位)。
/* copyright notice appears at beginning of ROM (in TEXT segment) */
.ascii "Copyright 1984-1997 Wind River Systems, Inc."
.align 2
■ 以上定義的版權申明字符串將出現(xiàn)在代碼段中。
■ 不清楚這個字符串的作用。
cold:
li r3, BOOT_COLD /* r3 = BOOT_COLD */
lis r4, HIADJ(start)
addi r4, r4, LO(start) /* r4 = @start */
lis r5, HIADJ(romInit)
addi r5, r5, LO(romInit) /* r5 = @romInit */
lis r6, HIADJ(ROM_TEXT_ADRS)
addi r6, r6, LO(ROM_TEXT_ADRS) /* r6 = ROM_TEXT_ADRS */
sub r4, r4, r5 /* r4 = r4 – r5 */
add r4, r4, r6 /* r4 = r4 + r6 */
■ 計算start在Flash中的位置,為:start-romInit+ROM_TEXT_ADRS。并跳轉到這個位置(下面)。為什么要這樣?
■ 由前面的分析可知,CPU從0xFFF00100啟動;由于在CPU看來,全部的4GB空間中的每個128K的塊都被映射到了Flash,所以0xFFF00100這個地址仍在Flash的偏移0x100處。這是起始狀態(tài),但不可能真的就把全部4GB空間都給Flash,在以后的初始化中,必定要把RAM,IMMR和外設等也要映射進來。做這些之前,需要把Flash的位置固定一下,比如映射到0xFE000000;方法是寫OR0和BR0寄存器。但在寫OR0時,CPU還在從0xFFF00000的那一塊取指令,而Flash就要被映射到0xFE000000塊,所以程序必定跑飛掉。所以,要對程序計數(shù)器(PC)進行調整。然而PC指針對程序員是不可見的,我們打算用跳轉指令修改它。
■ 不能直接跳轉到start處,必須自己計算地址。why?在鏈接時,我們曾指示ld將代碼段定位于RAM_HIGH_ADRS(bootrom;對vxWorks_rom是RAM_LOW_ADRS;參考相關的Makefile)。在我們的例子里RAM_HIGH_ADRS=0x00200000,即2M的地方。畢竟大部分代碼還要在RAM中執(zhí)行,是吧!現(xiàn)在的問題在于romInit也在代碼段中,但它是從ROM中執(zhí)行的(0xFE000100),而不是在連接器假定的位置執(zhí)行的。對連接器而言,符號romInit和start的值都是假定了程序在RAM中??梢韵胂?,對鏈接器而言,romInit=0x00200000,指向RAM區(qū)。同樣start也指向RAM區(qū)。欲得到start在ROM中的位置,計算方法就是start-romInit+ROM_TEXT_ADRS,其中ROM_TEXT_ADRS=0xFE000100。
■ 以上代碼叫PIC(Position Independent Code)。在程序將自身拷貝到RAM之前,需要注意。
■ 另外一個結論是,ROM映射到CPU地址空間何處都可以,只要不和其它東西沖突。
mtspr LR, r4
blr /* jump to flash mem adress */
■ 把r4值放入LR寄存器,利用blr跳轉到LR指定的地址。
■ 以上代碼似乎可以用以下代碼代替(?):
lis r4, HIADJ(start – romInit + ROM_TEXT_ADRS)
addi r4, r4, LO(start – romInit + ROM_TEXT_ADRS)
mtspr LR, r4
blr
start:
(略)
■ 以下進行系統(tǒng)初始化工作,包括:
初始化CPU核心寄存器;
禁止cache;
初始化IMMR;
初始化SIU;
初始化時鐘和中斷控制寄存器;
初始化CPM;
初始化UPM。等等。