龙芯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 //cuckoomtc0    zero, COP_0_CAUSE_REGli      t0, SR_BOOT_EXC_VEC     /* Exception to Boostrap Location */mtc0    t0, COP_0_STATUS_REG //cuckoo......bal     locate                  /* Get current execute address */nopuncached:or      ra, UNCACHED_MEMORY_ADDRj       ranop......locate:la      s0, uncachedsubu    s0, ra, s0mfc0    t0, CP0_STATUSli      t1, 0x64000000|SR_KX|SR_SX|SR_UX|SR_BOOT_EXC_VEC      # {cu3,cu2,cu1,cu0}<={0110, status_fr<=1,0xe0 to enable 64bit spaceor      t0, t0, t1mtc0    t0, CP0_STATUSmtc0    zero, COP_0_CAUSE_REG......                  #pcie配置bal     initserial       # 串口初始化函数nopPRINTSTR("\r\ninitserial good ^_^...\r\n")        #第一条打印信息nop......                   #内存初始化PRINTSTR("Copy PMON to execute location done.\r\n")move    a0, msizela      v0, initmips    #在zloader.ls2k/initmips.c中jalr    v0nop

困惑解答:

  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_STRlong 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_STRif ((str_sp < 0x9800000000000000) || (str_ra < 0xffffffff80000000)|| (str_flag != 0x5a5a5a5a5a5a5a5a)) {#endifwhile(1){if(run_unzip(biosdata,0x8f010000)>=0)break;}
#ifdef LS3A2H_STR}
#endiftgt_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 NOCACHE2flush_cache();
#elseflush_cache2();
#endifrealinitmips(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 > 0if (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 bitfbaddress |= 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 NSII9022Aconfig_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启动流程概述相关推荐

  1. 龙芯PMON(2K1000)启动流程(三、C语言部分③)

    3.6 NAND初始化 dbginit(NULL)执行完成后,说明重要的核心设备初始化过程已经告一段落.接下来设置把BEV清零. BEV1 BEV0 BEV in SR set to zero. (内 ...

  2. PMON学习记录2:PMON启动流程1

    PMON启动流程分析 B站有讯为电子的详细介绍视频,连接如下,十分推荐第一次学的看一下https://www.bilibili.com/video/BV13M4y1P7H8?p=7&vd_so ...

  3. 龙芯PMON(2K1000)启动流程(三、C语言部分②)

    3.3 tgt_devinit(Targets/LS2K/ls2k/tgt_machdep.c:699) tgt_devinit函数完成pmon阶段PCI设备的初始化,tgt_devinit调用了_p ...

  4. 龙芯PMON(2K1000)启动流程(二、汇编部分)

    1.pmon 文件相关的地址问题   cpu眼中的地址是虚拟地址,cpu 取指和取数据的地址是物理地址,经过北桥解释后的地址是总线地址,编译器产生的地址(包括解析了所有引用和重定位的符号后)为程序地址 ...

  5. 在x86_64平台上编译龙芯pmon

    编译环境 系统:deepin15.11 平台:x86_64 交叉编译器:gcc-4.4.7-7215-n64-loongson 搭建交叉编译环境 见在x86_64平台上搭建龙芯MIPS64交叉编译环境 ...

  6. uboot启动流程概述_关于RISCV启动部分的思考~

    1.本文说明 RISC-V的架构有着非常鲜明的特点,如果看过arm,aarch64,mips等架构的一些架构手册的基础知识,再看RISC-V的芯片的架构设计,就会觉得非常有意思,可以找到一些影子,但是 ...

  7. uboot启动流程概述_uboot 分析之 启动流程

    uboot的启动流程: 看一幅图: 1.第一阶段:start.s的内容: 点击(此处)折叠或打开 #include @该文件是第二步中mkconfig文件执行时创建的.include/config.h ...

  8. uboot启动流程概述_Alibaba Cloud Linux 2 LTS OS 启动优化实践

    Alibaba Cloud Linux 2 (原Aliyun Linux 2)是阿里云操作系统团队基于社区版 4.19 LTS 内核打造的一款针对云产品优化的下一代 Linux 操作系统发行版,不仅提 ...

  9. S3C2440上电启动流程概述

    一.S3C2440的启动方式 1.启动介质 S3C2440在上电时会通过判断OM0和OM1的信号组合来决定指令开始执行的位置(即引导ROM的位置),同时这两个信号也用于决定BANK0(nGCS0)的总 ...

  10. 龙芯PMON(2K1000)启动流程(一、总述)

    一.总流程 1.ls2k1000 cpu开始执行start.S(Targets/LS2K/ls2k/start.S)中的代码 2.然后跳转到 initmips(-)(zloader.ls2k/init ...

最新文章

  1. docker-ce 配置初始化后服务启动报错
  2. openEuler系统配置yum镜像源
  3. U盘从4G变为了75M 恢复U盘容量的方法
  4. can差分线阻抗_CAN总线冷知识—边沿台阶是怎么来的?
  5. 【PM模块】外包服务、工作清场管理、预防性维护
  6. javascript boolean/布尔表达式
  7. mysql下拉框记忆,Mysql alter语句记忆分析
  8. EasyExcel中输出为时间格式
  9. redis服务器信息统计,利用Redis统计网站在线活跃用户的方法
  10. 想换行做 5G 的开发者到底该咋办?
  11. 剑指offer面试题09. 用两个栈实现队列(队列、栈)
  12. 软件开发过程中的一些感悟
  13. 西门子plc cpu228 4路模拟量输入 2路模拟量输出
  14. 天然气故障代码大全_天然气发动机故障代码表(20130101)
  15. 三种局域网扫描工具比较
  16. 计算机应用毕业班主任鉴定,函授毕业生鉴定班主任鉴定范文.doc
  17. linux用户的目录结构,Linux下用户管理、目录结构
  18. c++ 线程函数(类成员函数作为线程函数使用)
  19. Mybatis从入门到精通(全)
  20. linux有必要清理内存么,Linux系统需要清理垃圾文件和优化系统吗?

热门文章

  1. 多个jQuery版本如何共存
  2. 图灵机:计算机世界的理论基石
  3. google四件套之Dagger2。从入门到爱不释手,之:Dagger2基础知识及在Java中使用(2)
  4. 欧派caxa设计软件_CAXA软件三维设计的基本使用方法
  5. java 获取yyyymmdd_从JS日期对象获取YYYYMMDD格式的字符串?
  6. hightopo学习笔记---入门
  7. UReport2导出word报错
  8. visio安装报错 1:1935 2:{XXXXXXXX...
  9. 推荐系统中传统模型——LightGBM + LR融合
  10. win10 linux 无法下载,大神为你win10系统无法安装ubuntu的处理