pmon启动流程概述
以龙芯处理器LS2K1000为例进行讲解
一 总体启动流程
- CPU执行start.S中的代码:ls2k1000 CPU开始执行Targets/LS2K/ls2k/start.S中的代码。这段代码是PMON启动的起点,它包含了一些宏定义、程序入口指示和CPU初始化所需的指令。
- 跳转到init_loongarch函数:然后,代码会跳转到zloader.ls2k/init_loongarch.c中的init_loongarch函数中执行。在这个函数中,PMON会将BIOS数据(biosdata)解压到特定的内存地址上。
- 调用realinit_loongarch函数:接下来调用zloader.ls2k/init_loongarch.c中的realinit_loongarch函数,跳转到Targets/LS2K/ls2k/tgt_machdep.c中的init_loongarch函数。在这个阶段,PMON会完成更多的初始化工作,并准备跳转到C语言编写的代码部分。
- 执行C语言代码:一旦PMON跳转到内存中的代码,它就可以使用栈和C语言编写的函数了。接下来的代码会继续进行硬件初始化、环境变量设置、PCI设备初始化等工作,并最终加载和执行操作系统内核。
为了更好的理解启动流程,以下是对pmon.bin.c生成过程的详细解释,以及它如何与biosdata和gzrom.bin相关联:
pmon.bin.c的生成过程
1.编译PMON源码:
- 首先,需要编译ls2k的PMON源码。PMON是一种固件,用于处理处理器的启动和电源管理。
- 在编译过程中,会生成多个目标文件(*.o),这些文件位于Targets/LS2K/compile/ls2k目录下。
2.链接生成elf文件:
- 使用链接脚本(如Targets/LS2K/conf/ld.script)将这些目标文件链接成一个elf格式的文件,即pmon。
- 这个elf文件包含了PMON的所有代码和数据。
3.去除符号表并压缩:
- elf文件通常包含符号表,这些符号表在最终的产品中是不需要的。因此,需要去除符号表,得到pmon.bin文件。
- 接着,使用gzip命令对pmon.bin文件进行压缩,得到pmon.bin.gz文件。
4.转换为C数组:
- 为了将pmon.bin.gz文件嵌入到C代码中,使用bin2c工具将其转换为一个C数组。这个数组就是biosdata,它保存在pmon.bin.c文件中。
- 在这个过程中,pmon.bin.gz文件的内容被读取并转换为一个字符数组的形式,这个数组在C代码中可以被直接访问和使用。
biosdata与gzrom.bin的关联
1.biosdata的作用:
- biosdata是一个在pmon.bin.c文件中定义的数组,它包含了PMON固件的所有代码和数据(经过压缩)。
- 在PMON的启动过程中,这个数组会被解压并加载到内存中,以执行PMON的代码。
2.gzrom.bin的生成:
- gzrom.bin文件是通过将zload.o和start.o等文件链接而成,并去除了符号表得到的。
- 其中,zload.o包含了initmips.c和pmon.bin.c等文件的编译结果,而pmon.bin.c文件又包含了biosdata数组。
- 因此,gzrom.bin文件间接地包含了biosdata数组的内容。
3.启动流程中的使用:
- 在龙芯处理器的启动过程中,gzrom.bin文件会被加载到内存中,并解压执行其中的代码。
- 这个过程中,会跳转到initmips函数中执行,而initmips函数又会使用到biosdata数组中的数据来初始化PMON固件。
二 start.S 启动概述
- .globl _start
- .globl start
- .globl __main
- _start:
- start:
- .globl stack
- stack = start + LOCK_CACHE_SIZE /* Place PMON stack in the end of 2M RAM */
复制代码
三 在zloader.ls2k/init_loongarch.c中init_loongarch(…) 概述
- void realinit_loongarch();
- void init_loongarch(unsigned long long msize)
- {
- unsigned long i;
- char * biosdata_flash = (unsigned long long)biosdata & 0xfffffULL | 0x1c000000ULL | (0x900000000f010000 & (0xffULL << 56));
- char * biosdata_mem = (0x900000000f010000 - sizeof(biosdata)) & ~0xffULL;
- early_printf("Copy Bios to memory "); //Copy the biosdata from flash to the memory
- for (i = 0; i < sizeof(biosdata); i += sizeof(unsigned long)) {
- *(volatile unsigned long*)(biosdata_mem + i) = *(volatile unsigned long*)(biosdata_flash + i);
- }
- early_printf("OK, Uncompressing Bios");
- while(1) {
- if(run_unzip(biosdata_mem, 0x900000000f010000) >= 0)
- break;
- }
- memset((void *)0x900000000f27a228, 0, 0x900000000f2ec678 - 0x900000000f27a228); //clear bss
- memset((void *)0x900000000f010000 - 0x1000, 0, 0x1000); //0x900000000f010000-0x1000 for frame(registers),memset for pretty
- early_printf("OK, Booting Bios\r\n");
- realinit_loongarch(msize);
- }
- void realinit_loongarch(unsigned long long msize)
- {
- __asm__ ("li.d $r3,0x900000000f010000-0x4000;\n" \
- " li.d $r12,0x900000000f0af8f0;\n" \ <b>//该地址就是Targets/LS2K/ls2k/tgt_machdep.c中的<span style="background-color: rgb(255, 255, 255);">init_loongarch</span>(...)函数地址</b>
- " move $r4,%0;\n" \
- " jirl $r0,$r12, 0;\n" \
- :
- : "r" (msize)
- : "$r3", "$r12");
- }
复制代码
2.函数 realinit_loongarch(unsigned long long msize)
- 参数: msize - 内存大小,传递给BIOS初始化函数。
- 功能: 使用内联汇编跳转到BIOS的初始化函数。
四 在Targets/LS2K/ls2k/tgt_machdep.c中 init_loongarch(…)概述
- void init_loongarch(unsigned long long tgt_memsz)
- {
- unsigned int hi;
- unsigned short i;
- unlock_scache(LOCK_CACHE_BASE, LOCK_CACHE_SIZE);
- //core1 run wait_for_smp_call function in ram
- asm volatile("st.d %1,%0,0x20;"::"r"(0x800000001fe01100),"r"(&slave_main));
- mem_win_cfg(tgt_memsz);
- #ifdef CONFIG_UART0_SPLIT
- readq(LS2K1000_GENERAL_CFG1) |= 0xe;
- #endif
- /*enable float */
- tgt_fpuenable();
- get_memorysize(tgt_memsz);
- mul_pin_def_cfg();
- /*
- * Probe clock frequencys so delays will work properly.
- */
- ls2k_i2c_init(0, LS2K1000_I2C0_REG_BASE);
- ls2k_i2c_init(0, LS2K1000_I2C1_REG_BASE);
- tgt_cpufreq();
- SBD_DISPLAY("DONE", 0);
- /*
- * Init PMON and debug
- */
- cpuinfotab[0] = &DBGREG;
- dbginit(NULL);
- bcopy(LoongArchException, (char *)GEN_EXC_VEC, LoongArchExceptionEnd - LoongArchException);
- cpu_set_ebase();
- cpu_set_tlb_ebase();
- tgt_printf("set ebase done\n");
- /*
- * Set up exception vectors.
- */
- SBD_DISPLAY("BEV1", 0);
- printf("BEV in SR set to zero.\n");
- #if NNAND
- #ifdef CONFIG_LS2K_NAND
- readq(LS2K1000_GENERAL_CFG0) |= (1 << 9);
- ls2k_nand_init();
- #else
- /*nand pin as gpio*/
- readq(LS2K1000_GENERAL_CFG0) &= ~(1 << 9);
- #endif
- #if NSPINAND_MT29F || NSPINAND_LLD
- ls2k_spi_nand_probe();
- #endif
- #if NM25P80
- ls2k_m25p_probe();
- #endif
- #else
- /*nand pin as gpio*/
- readq(LS2K1000_GENERAL_CFG0) &= ~(1 << 9);
- #endif
- #ifdef DTB
- verify_dtb();
- #endif
- clear_pcie_inter_irq();
- /*
- * Launch!
- */
- main();
- }
复制代码
|
-
|