龙芯pmon启动流程概述

龙芯pmon启动流程概述

以龙芯处理器LS2K1000为例进行讲解

一、总体介绍pmon启动流程

  1. ls2k1000 cpu开始执行start.S(Targets/LS2K/ls2k/start.S)中的代码
  2. 然后跳转到 initmips(…)(zloader.ls2k/initmips.c) 函数中执行
  3. 在initmips()(zloader.ls2k/initmips.c)函数中将biosdata解压到0x8f010000地址上
  4. 然后调用realinitmios(…)函数跳转到Targets/LS2K/ls2k/tgt_machdep.c中的initmips(…)

困惑解答:

  1. biosdata是什么?
    想搞清这个问题,就要了解gzrom.bin是怎么生成的
    gzrom.bin 是gzrom去掉符号表得到
    gzrom是zload.o和start.o通过ld.script链接而成
    start.o是Targets/LS2K/ls2k/start.S编译生成
    zload.o是由zloader.c 、inflate.c、malloc.c、memop.c、initmips.c、pmon.bin.c 编译生成(initmips.c、pmon.bin.c编译过程中生成),这些 *.c 文件都在zloader.ls2k目录下
    在initmips(…)(zloader.ls2k/initmips.c)函数中使用biosdata,而biosdata是在pmon.bin.c 里定义的数组
    至此知道了biosdata是一个定义在pmon.bin.c文件里的数组
  2. pmon.bin.c是如何生成的?
    在成功编译ls2k pmon源码后,在Targets/LS2K/compile/下生成ls2k目录,该目录下的 *.o 会链接成elf文件pmon,生成该elf文件pmon需要链接 Targets/LS2K/conf/ld.script文件。elf文件pmon去掉符号表后得到pmon.bin文件,通过命令gzip、bin2c将pmon.bin文件生成一个数组biosdata,该数组保存到pmon.bin.c文件里。

二、start.S 启动概述

        .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

困惑解答:

  1. pcie配置、内存初始化是否有详细讲解?
    没有

三、在zloader.ls2k/initmips.c中 initmips(…) 概述

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");

}

困惑解答:

  1. 我的realinitmips(…)函数里的地址怎么不是0x8f0d4b18?
    每次编译链接后,会获取实际Targets/LS2K/ls2k/tgt_machdep.c中的initmips(…)函数地址,放到realinitmips(…)函数里。

  2. 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)

四、在Targets/LS2K/ls2k/tgt_machdep.c中 initmips (…)概述

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();
}

1、dbginit(NULL) 函数

void dbginit (char *adr)
{
	__init();       /* Do all constructor initialisation */
	
	envinit();		//设置环境变量
	
	tgt_devinit();
	
	init_net(1);

	tgt_logo();
	
	print_cpu_info();
	print_mem_freq();
}
1.1、envinit()函数
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);
        }
    }
}
1.2、tgt_devinit()函数
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);
        }
}
1.2.1、_pci_hwinit(…)函数
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);
}
1.2.2、_pci_scan_dev(…)函数
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);
        }
}
1.2.2.1、 _pci_scan_dev(…)函数
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 */
}
1.2.1.3、_setup_pcibuses(…)函数
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);
        }
    }
}
1.3 、init_net(1)函数
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);
        }
}
1.3.1、tgt_devconfig()函数
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);
}

2、main()函数

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 (…)总体概述

=>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);

你可能感兴趣的:(龙芯,pmon启动流程)