[X]关闭

pmon启动流程概述

文档创建者:LINUX课程
浏览次数:9
最后更新:2024-11-22
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 启动概述
image.jpg
  1. .globl        _start
  2.         .globl        start
  3.         .globl        __main
  4. _start:
  5. start:
  6.         .globl        stack
  7. stack = start + LOCK_CACHE_SIZE         /* Place PMON stack in the end of 2M RAM */
复制代码


三 在zloader.ls2k/init_loongarch.c中init_loongarch(…) 概述
image.jpg

  1. void realinit_loongarch();
  2. void init_loongarch(unsigned long long msize)
  3. {
  4.         unsigned long i;
  5.         char * biosdata_flash = (unsigned long long)biosdata & 0xfffffULL | 0x1c000000ULL | (0x900000000f010000 & (0xffULL << 56));
  6.         char * biosdata_mem = (0x900000000f010000 - sizeof(biosdata)) & ~0xffULL;

  7.         early_printf("Copy Bios to memory ");        //Copy the biosdata from flash to the memory
  8.         for (i = 0; i < sizeof(biosdata); i += sizeof(unsigned long)) {
  9.                 *(volatile unsigned long*)(biosdata_mem + i) = *(volatile unsigned long*)(biosdata_flash + i);
  10.         }
  11.         early_printf("OK, Uncompressing Bios");
  12.         while(1) {
  13.                 if(run_unzip(biosdata_mem, 0x900000000f010000) >= 0)
  14.                         break;
  15.         }
  16.         memset((void *)0x900000000f27a228, 0, 0x900000000f2ec678 - 0x900000000f27a228);        //clear bss
  17.         memset((void *)0x900000000f010000 - 0x1000, 0, 0x1000);        //0x900000000f010000-0x1000 for frame(registers),memset for pretty
  18.         early_printf("OK, Booting Bios\r\n");
  19.         realinit_loongarch(msize);
  20. }


  21. void realinit_loongarch(unsigned long long msize)
  22. {
  23.         __asm__ ("li.d  $r3,0x900000000f010000-0x4000;\n" \
  24.                 "        li.d $r12,0x900000000f0af8f0;\n" \      <b>//该地址就是Targets/LS2K/ls2k/tgt_machdep.c中的<span style="background-color: rgb(255, 255, 255);">init_loongarch</span>(...)函数地址</b>
  25.                 "        move $r4,%0;\n" \

  26.                 "        jirl $r0,$r12, 0;\n" \
  27.                 :
  28.                   : "r" (msize)
  29.                 : "$r3", "$r12");
  30. }
复制代码



2.函数 realinit_loongarch(unsigned long long msize)
  • 参数: msize - 内存大小,传递给BIOS初始化函数。
  • 功能: 使用内联汇编跳转到BIOS的初始化函数。



四 在Targets/LS2K/ls2k/tgt_machdep.c中 init_loongarch(…)概述
image.jpg
  1. void init_loongarch(unsigned long long tgt_memsz)
  2. {
  3.         unsigned int hi;
  4.         unsigned short i;

  5.         unlock_scache(LOCK_CACHE_BASE, LOCK_CACHE_SIZE);
  6.         //core1 run wait_for_smp_call function in ram
  7.         asm volatile("st.d %1,%0,0x20;"::"r"(0x800000001fe01100),"r"(&slave_main));

  8.         mem_win_cfg(tgt_memsz);

  9. #ifdef CONFIG_UART0_SPLIT
  10.         readq(LS2K1000_GENERAL_CFG1) |= 0xe;
  11. #endif
  12.         /*enable float */
  13.         tgt_fpuenable();

  14.         get_memorysize(tgt_memsz);

  15.         mul_pin_def_cfg();

  16.         /*
  17.          *  Probe clock frequencys so delays will work properly.
  18.          */

  19.     ls2k_i2c_init(0, LS2K1000_I2C0_REG_BASE);
  20.     ls2k_i2c_init(0, LS2K1000_I2C1_REG_BASE);
  21.         tgt_cpufreq();
  22.         SBD_DISPLAY("DONE", 0);

  23.         /*
  24.          *  Init PMON and debug
  25.          */
  26.         cpuinfotab[0] = &DBGREG;

  27.         dbginit(NULL);

  28.         bcopy(LoongArchException, (char *)GEN_EXC_VEC, LoongArchExceptionEnd - LoongArchException);
  29.         cpu_set_ebase();
  30.         cpu_set_tlb_ebase();
  31.         tgt_printf("set ebase done\n");

  32.         /*
  33.          *  Set up exception vectors.
  34.          */
  35.         SBD_DISPLAY("BEV1", 0);
  36.         printf("BEV in SR set to zero.\n");

  37. #if NNAND
  38. #ifdef CONFIG_LS2K_NAND
  39.         readq(LS2K1000_GENERAL_CFG0) |= (1 << 9);
  40.         ls2k_nand_init();
  41. #else
  42.         /*nand pin as gpio*/
  43.         readq(LS2K1000_GENERAL_CFG0) &= ~(1 << 9);
  44. #endif
  45. #if NSPINAND_MT29F || NSPINAND_LLD
  46.         ls2k_spi_nand_probe();
  47. #endif
  48. #if NM25P80
  49.         ls2k_m25p_probe();
  50. #endif
  51. #else
  52.         /*nand pin as gpio*/
  53.         readq(LS2K1000_GENERAL_CFG0) &= ~(1 << 9);
  54. #endif

  55. #ifdef DTB
  56.         verify_dtb();
  57. #endif
  58.         clear_pcie_inter_irq();

  59.         /*
  60.          * Launch!
  61.          */
  62.         main();
  63. }
复制代码

image.jpg
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则