以龙芯处理器LS2K1000为例进行讲解
困惑解答:
.set noreorder
.globl _start
.globl start
.globl __main
_start:
start:
.globl stack
stack = start - 0x4000 /* Place PMON stack below PMON start in RAM */
/*set all spi cs to 1, default input*/
/* init processor state at first*/
/* NOTE!! Not more that 16 instructions here!!! Right now it's FULL! */
mtc0 zero, COP_0_STATUS_REG //cuckoo
mtc0 zero, COP_0_CAUSE_REG
li t0, SR_BOOT_EXC_VEC /* Exception to Boostrap Location */
mtc0 t0, COP_0_STATUS_REG //cuckoo
......
bal locate /* Get current execute address */
nop
uncached:
or ra, UNCACHED_MEMORY_ADDR
j ra
nop
......
locate:
la s0, uncached
subu s0, ra, s0
mfc0 t0, CP0_STATUS
li t1, 0x64000000|SR_KX|SR_SX|SR_UX|SR_BOOT_EXC_VEC # {cu3,cu2,cu1,cu0}<={0110, status_fr<=1,0xe0 to enable 64bit space
or t0, t0, t1
mtc0 t0, CP0_STATUS
mtc0 zero, COP_0_CAUSE_REG
...... #pcie配置
bal initserial # 串口初始化函数
nop
PRINTSTR("\r\ninitserial good ^_^...\r\n") #第一条打印信息
nop
...... #内存初始化
PRINTSTR("Copy PMON to execute location done.\r\n")
move a0, msize
la v0, initmips #在zloader.ls2k/initmips.c中
jalr v0
nop
困惑解答:
void initmips(unsigned long long msize,unsigned long long dmsize, unsigned long long dctrl)
{
long *edata=(void *)0x8f25fd94;
long *end=(void *)0x8f2a2660;
int *p;
int debug=(msize==0);
#ifdef LS3A2H_STR
long long str_ra,str_flag,str_sp;
str_ra = *((long long*)0xafaaa040);
str_sp = *((long long*)0xafaaa048);
str_flag = *((long long*)0xafaaa050);
#endif
// CPU_TLBClear();
tgt_puts("Uncompressing Bios");
if(!debug||dctrl&1)enable_cache();
#ifdef LS3A2H_STR
if ((str_sp < 0x9800000000000000) || (str_ra < 0xffffffff80000000)
|| (str_flag != 0x5a5a5a5a5a5a5a5a)) {
#endif
while(1)
{
if(run_unzip(biosdata,0x8f010000)>=0)break;
}
#ifdef LS3A2H_STR
}
#endif
tgt_puts("OK,Booting Bios\r\n");
for(p=edata;p<=end;p++)
{
*p=0;
}
memset(0x8f010000-0x1000,0,0x1000);//0x8f010000-0x1000 for frame(registers),memset for pretty
#ifdef NOCACHE2
flush_cache();
#else
flush_cache2();
#endif
realinitmips(debug?dmsize:msize);
}
void realinitmips(unsigned long long msize)
{
asm ("li $29,0x8f010000-0x4000;\n" \
" li $2,0x8f0d4b18;\n" \ //该地址就是Targets/LS2K/ls2k/tgt_machdep.c中的initmips(...)函数地址
" move $4,%0;\n" \
" jalr $2;\n" \
" nop;\n" \
" 1: b 1b;nop;" \
:
: "r" (msize)
: "$29", "$2","$4");
}
困惑解答:
我的realinitmips(…)函数里的地址怎么不是0x8f0d4b18?
每次编译链接后,会获取实际Targets/LS2K/ls2k/tgt_machdep.c中的initmips(…)函数地址,放到realinitmips(…)函数里。
zloader.ls2k/initmips.c是如何生成的?
细心的朋友发现了zloader.ls2k/initmips.c文件是编译后生成的,并不是pmon源码原有的。zloader.ls2k/initmips.c是通过zloader.ls2k/genrom生成的,genrom是perl语言编写的脚本,该脚本获取了Targets/LS2K/compile/ls2k/pmon(elf)文件中的符号表(myedata、myend、mystart、myinitmips)
void initmips(unsigned long long raw_memsz)
{
get_memorysize(raw_memsz);
ls2k_i2c_init(0, 0xbfe01000+0*0x800);
dbginit(NULL); //大部分初始化在这个函数里
bcopy(MipsException, (char *)XTLB_MISS_EXC_VEC, MipsExceptionEnd - MipsException);
bcopy(MipsException, (char *)GEN_EXC_VEC, MipsExceptionEnd - MipsException);
ls2k_nand_init(); //nand初始化
ls2k_m25p_probe(); //m25p80初始化
main();
}
void dbginit (char *adr)
{
__init(); /* Do all constructor initialisation */
envinit(); //设置环境变量
tgt_devinit();
init_net(1);
tgt_logo();
print_cpu_info();
print_mem_freq();
}
void envinit()
{
tgt_mapenv(_setenv);
/* set defaults (only if not set at all) */
for (i = 0; stdenvtab[i].name; i++) {
if (!getenv(stdenvtab[i].name)) {
setenv(stdenvtab[i].name, stdenvtab[i].init);
}
}
}
void tgt_devinit()
{
_pci_businit(1); /* PCI bus initialization */
}
void _pci_businit(int init)
{
/* intialise the PCI bridge */
if (/*init*/ 1) {
init = _pci_hwinit(init, &def_bus_iot, &def_bus_memt);
}
if(monarch_mode) {
for(i = 0, pb = _pci_head; i < pci_roots; i++, pb = pb->next) {
pb->bridge.pribus_num = i?++_pci_nbus:_pci_nbus;
_pci_scan_dev(pb, pb->bridge.pribus_num, 0, init);
}
_setup_pcibuses(init);
}
}
int
_pci_hwinit(initialise, iot, memt)
int initialise;
bus_space_tag_t iot;
bus_space_tag_t memt;
{
/*
* Allocate and initialize PCI bus heads.
*/
/*
* PCI Bus 0
*/
pd = pmalloc(sizeof(struct pci_device));
pb = pmalloc(sizeof(struct pci_bus));
pd->pa.pa_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
pd->pa.pa_iot = pmalloc(sizeof(bus_space_tag_t));
pd->pa.pa_iot->bus_reverse = 1;
pd->pa.pa_iot->bus_base = BONITO_PCIIO_BASE_VA;
pd->pa.pa_memt = pmalloc(sizeof(bus_space_tag_t));
pd->pa.pa_memt->bus_reverse = 1;
pd->pa.pa_memt->bus_base = 0xc0000000;
pd->pa.pa_dmat = &bus_dmamap_tag;
pd->bridge.secbus = pb;
_pci_head = pd;
/*set pci base0 address and window size*/
pci_local_mem_pci_base = 0x0;
return(1);
}
static void
_pci_scan_dev(struct pci_device *dev, int bus, int device, int initialise)
{
for(; device < 32; device++) {
_pci_query_dev(dev, bus, device, initialise);
}
}
static void
_pci_query_dev(struct pci_device *dev, int bus, int device, int initialise)
{
_pci_query_dev_func(dev, tag, initialise);
}
static void
_pci_query_dev_func (struct pci_device *dev, pcitag_t tag, int initialise)
{
_pci_break_tag (tag, &bus, &device, &function);
pd->pa.pa_bus = bus;
pd->pa.pa_device = device;
pd->pa.pa_function = function;
pd->pa.pa_tag = tag;
pd->pa.pa_id = id;
pd->pa.pa_class = class;
pd->pa.pa_flags = PCI_FLAGS_IO_ENABLED | PCI_FLAGS_MEM_ENABLED;
pd->pa.pa_iot = dev->pa.pa_iot;
pd->pa.pa_memt = dev->pa.pa_memt;
pd->pa.pa_dmat = dev->pa.pa_dmat;
pd->parent = dev;
pd->pcibus = dev->bridge.secbus;
pb = pd->pcibus;
_pci_device_insert(dev, pd);
/*
* Check to see if device is a PCI Bridge
*/
if (PCI_ISCLASS(class, PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_PCI)) {
set_pcie_port_type(pd);
/* Scan secondary bus of the bridge */
_pci_scan_dev(pd, pd->bridge.secbus_num, 0, initialise);
/*
* Sum up the address space needed by secondary side of bridge
*/
/* Sum up I/O Space needed */
/* Sum up Memory Space needed */
/* Round to minimum granularity requierd for a bridge */
/* Round to minimum granularity requierd for a bridge */
}
else if (PCI_ISCLASS(class, PCI_CLASS_MASS_STORAGE, PCI_SUBCLASS_MASS_STORAGE_IDE) &&
dev->bridge.secbus->minpciioaddr == 0) {
/*
* There is no need to setup memory regions for IDE storage devices
* but only if PCI/ISA I/O space is accessables
*/
return;
}
//set BAR for this dev
/* Finally check for Expansion ROM */
}
static void
_setup_pcibuses(int initialise)
{
/* setup the individual device windows */
SBD_DISPLAY ("PCIW", CHKPNT_PCIW);
for(i = 0, pd = _pci_head; i < pci_roots; i++, pd = pd->next) {
_pci_setup_windows(pd);
}
}
static void
_pci_setup_windows(struct pci_device *dev)
{
/* Recursive allocate memory for secondary buses */
for(pd = dev->bridge.child; pd != NULL; pd = pd->next) {
if (PCI_ISCLASS(pd->pa.pa_class, PCI_CLASS_BRIDGE, PCI_SUBCLASS_BRIDGE_PCI)) {
_pci_setup_windows(pd);
}
}
}
void
init_net (int hwok)
{
/*
* Initialise network devices and protocols
*/
if (hwok) {
s = splhigh();
tgt_devconfig();
for (pdev = pdevinit; pdev->pdev_attach != NULL; pdev++) {
if (pdev->pdev_count > 0) {
(*pdev->pdev_attach)(pdev->pdev_count);
}
}
ifinit();
printf("ifinit done.\n");
domaininit();
printf("domaininit done.\n");
splx(s);
}
}
void tgt_devconfig()
{
/* Enable pci device and init VGA device */
init_pcidev();
config_init();
configure();
}
static void init_pcidev(void)
{
_pci_devinit(1); /* PCI device initialization */
if(pcie_dev != NULL){
SBD_DISPLAY("VGAI", 0);
rc = vga_bios_init();
}
#if NMOD_FRAMEBUFFER > 0
if (rc > 0) {
if(pcie_dev == NULL){
printf("begin fb_init\n");
fbaddress = dc_init();
printf("dc_init done\n");
//this parameters for 1280*1024 VGA
} else {
fbaddress = _pci_conf_read(pcie_dev->pa.pa_tag,0x10);
fbaddress = fbaddress &0xffffff00; //laster 8 bit
fbaddress |= 0x80000000;
}
printf("fbaddress = %08x\n", fbaddress);
fb_init(fbaddress, 0);
printf("fb_init done\n");
} else {
printf("vga bios init failed, rc=%d\n",rc);
}
#if NSII9022A
config_sii9022a();
#endif
#endif
}
void
configure()
{
if(config_rootfound("mainbus", "mainbus") == 0)
}
struct device *
config_rootfound(rootname, aux)
char *rootname;
void *aux;
{
if ((match = config_rootsearch((cfmatch_t)NULL, rootname, aux)) != NULL)
return (config_attach(ROOT, match, aux, (cfprint_t)NULL));
}
void *
config_rootsearch(fn, rootname, aux)
register cfmatch_t fn;
register char *rootname;
register void *aux;
{
register struct cfdata *cf;
register short *p;
struct matchinfo m;
m.fn = fn;
m.parent = ROOT;
m.match = NULL;
m.aux = aux;
m.indirect = 0;
m.pri = 0;
/*
* Look at root entries for matching name. We do not bother
* with found-state here since only one root should ever be
* searched (and it must be done first).
*/
for (p = cfroots; *p >= 0; p++) {
cf = &cfdata[*p];
if (strcmp(cf->cf_driver->cd_name, rootname) == 0)
mapply(&m, cf);
}
return (m.match);
}
void
mapply(m, cf)
register struct matchinfo *m;
register struct cfdata *cf;
{
pri = (*cf->cf_attach->ca_match)(m->parent, match, m->aux);
}
struct device *
config_attach(parent, match, aux, print)
register struct device *parent;
void *match;
register void *aux;
cfprint_t print;
{
(*ca->ca_attach)(parent, dev, aux);
}
int
main()
{
save_board_ddrparam(0);
load_menu_list();
s = getenv("al1");
ret = autoload(s);
if (ret == 1) {
s = getenv("al");
ret = autoload(s);
}
while(1) {
strncpy (prompt, getenv ("prompt"), sizeof(prompt));
printf("%s", prompt);
get_line(line, 0);
do_cmd(line);
console_state(1);
}
DeviceRelease();
return(0);
}
=>initmips(raw_memsz)
=>dbginit(NULL);
=>__init();
envinit();
=>tgt_mapenv(_setenv);
getenv()
setenv()
tgt_devinit();
=>_pci_businit(1);
=>_pci_hwinit(init, &def_bus_iot, &def_bus_memt);
_pci_scan_dev(pb, pb->bridge.pribus_num, 0, init);
=>_pci_query_dev(dev, bus, device, initialise);
=>_pci_query_dev_func(dev, tag, initialise);
=>_pci_scan_dev(...);
_setup_pcibuses(init);
=>_pci_setup_windows(pd);
_pci_setup_windows(pd);
init_net(1);
=>tgt_devconfig();
=>_pci_devinit(1);
=>_pci_setup_devices(pd, initialise);
_pci_setup_devices(pd, initialise);
config_init();
=>TAILQ_INIT(...);
TAILQ_INSERT_TAIL(...);
configure();
=>config_rootfound("mainbus", "mainbus");
=>config_rootsearch(...)
=>mapply(&m, cf);
=>(*cf->cf_attach->ca_match)(...)
=>mainbus_attach(...)
=>config_found(...)
config_attach(...);
=>(*ca->ca_attach)(parent, dev, aux);
tgt_logo();
ls2k_nand_init();
main();
=>load_menu_list();
autoload(s);