龙芯pmon启动流程概述
龙芯pmon启动流程概述
以龙芯处理器LS2K1000为例进行讲解
一、总体介绍pmon启动流程
- ls2k1000 cpu开始执行start.S(Targets/LS2K/ls2k/start.S)中的代码
- 然后跳转到 initmips(…)(zloader.ls2k/initmips.c) 函数中执行
- 在initmips()(zloader.ls2k/initmips.c)函数中将biosdata解压到0x8f010000地址上
- 然后调用realinitmios(…)函数跳转到Targets/LS2K/ls2k/tgt_machdep.c中的initmips(…)
困惑解答:
- 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文件里的数组 - 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
困惑解答:
- 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");}
困惑解答:
我的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)
四、在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启动流程概述相关推荐
- 龙芯PMON(2K1000)启动流程(三、C语言部分③)
3.6 NAND初始化 dbginit(NULL)执行完成后,说明重要的核心设备初始化过程已经告一段落.接下来设置把BEV清零. BEV1 BEV0 BEV in SR set to zero. (内 ...
- PMON学习记录2:PMON启动流程1
PMON启动流程分析 B站有讯为电子的详细介绍视频,连接如下,十分推荐第一次学的看一下https://www.bilibili.com/video/BV13M4y1P7H8?p=7&vd_so ...
- 龙芯PMON(2K1000)启动流程(三、C语言部分②)
3.3 tgt_devinit(Targets/LS2K/ls2k/tgt_machdep.c:699) tgt_devinit函数完成pmon阶段PCI设备的初始化,tgt_devinit调用了_p ...
- 龙芯PMON(2K1000)启动流程(二、汇编部分)
1.pmon 文件相关的地址问题 cpu眼中的地址是虚拟地址,cpu 取指和取数据的地址是物理地址,经过北桥解释后的地址是总线地址,编译器产生的地址(包括解析了所有引用和重定位的符号后)为程序地址 ...
- 在x86_64平台上编译龙芯pmon
编译环境 系统:deepin15.11 平台:x86_64 交叉编译器:gcc-4.4.7-7215-n64-loongson 搭建交叉编译环境 见在x86_64平台上搭建龙芯MIPS64交叉编译环境 ...
- uboot启动流程概述_关于RISCV启动部分的思考~
1.本文说明 RISC-V的架构有着非常鲜明的特点,如果看过arm,aarch64,mips等架构的一些架构手册的基础知识,再看RISC-V的芯片的架构设计,就会觉得非常有意思,可以找到一些影子,但是 ...
- uboot启动流程概述_uboot 分析之 启动流程
uboot的启动流程: 看一幅图: 1.第一阶段:start.s的内容: 点击(此处)折叠或打开 #include @该文件是第二步中mkconfig文件执行时创建的.include/config.h ...
- uboot启动流程概述_Alibaba Cloud Linux 2 LTS OS 启动优化实践
Alibaba Cloud Linux 2 (原Aliyun Linux 2)是阿里云操作系统团队基于社区版 4.19 LTS 内核打造的一款针对云产品优化的下一代 Linux 操作系统发行版,不仅提 ...
- S3C2440上电启动流程概述
一.S3C2440的启动方式 1.启动介质 S3C2440在上电时会通过判断OM0和OM1的信号组合来决定指令开始执行的位置(即引导ROM的位置),同时这两个信号也用于决定BANK0(nGCS0)的总 ...
- 龙芯PMON(2K1000)启动流程(一、总述)
一.总流程 1.ls2k1000 cpu开始执行start.S(Targets/LS2K/ls2k/start.S)中的代码 2.然后跳转到 initmips(-)(zloader.ls2k/init ...
最新文章
- docker-ce 配置初始化后服务启动报错
- openEuler系统配置yum镜像源
- U盘从4G变为了75M 恢复U盘容量的方法
- can差分线阻抗_CAN总线冷知识—边沿台阶是怎么来的?
- 【PM模块】外包服务、工作清场管理、预防性维护
- javascript boolean/布尔表达式
- mysql下拉框记忆,Mysql alter语句记忆分析
- EasyExcel中输出为时间格式
- redis服务器信息统计,利用Redis统计网站在线活跃用户的方法
- 想换行做 5G 的开发者到底该咋办?
- 剑指offer面试题09. 用两个栈实现队列(队列、栈)
- 软件开发过程中的一些感悟
- 西门子plc cpu228 4路模拟量输入 2路模拟量输出
- 天然气故障代码大全_天然气发动机故障代码表(20130101)
- 三种局域网扫描工具比较
- 计算机应用毕业班主任鉴定,函授毕业生鉴定班主任鉴定范文.doc
- linux用户的目录结构,Linux下用户管理、目录结构
- c++ 线程函数(类成员函数作为线程函数使用)
- Mybatis从入门到精通(全)
- linux有必要清理内存么,Linux系统需要清理垃圾文件和优化系统吗?
热门文章
- 多个jQuery版本如何共存
- 图灵机:计算机世界的理论基石
- google四件套之Dagger2。从入门到爱不释手,之:Dagger2基础知识及在Java中使用(2)
- 欧派caxa设计软件_CAXA软件三维设计的基本使用方法
- java 获取yyyymmdd_从JS日期对象获取YYYYMMDD格式的字符串?
- hightopo学习笔记---入门
- UReport2导出word报错
- visio安装报错 1:1935 2:{XXXXXXXX...
- 推荐系统中传统模型——LightGBM + LR融合
- win10 linux 无法下载,大神为你win10系统无法安装ubuntu的处理