深圳市航顺芯片技术研发有限公司
直播中

技术牛人小渣子

13年用户 804经验值
私信 关注
[问答]

PMON目录结构解析

argets目录是由哪些部分组成的?
与CPU相关的一些宏定义有哪些?

回帖(1)

李思昊

2021-10-25 16:49:22
  http://xenyinzen.wikidot.com/loongson-about
  +++++++++++++++++++++++++++++++++++++++++
  PMON-V1.1 目录结构
  +++++++++++++++++++++++++++++++++++++++++
  pmon的目录结构大致如下(由linux工具tree生成)
  。
  |-- Targets 目标结构相关代码,每个新结构在该目录下有一个子目录
  | -- Bonito Bonito是我们的北桥代号,里面是一些关于北桥的代码 | |-- Bonito | |-- compile | |– zboot
  | | |-- images
  | | |-- pmon
  | | -- utils | |-- conf | |-- dev | |-- include |– pci
  |-- conf 源代码编译所依赖的配置文件所在目录
  |-- doc 说明文档
  |-- examples 一看就知道是样例,但我还不知道只面究竟写的是什么
  |-- fb 在frambuffer上做文字和图形显示的代码
  |-- include 系统头文件
  |-- lib
  | |-- libc C库
  | -- libz zip压缩库 |-- pic 开机启动图片(压缩后的)存放目录 |-- pmon pmon主体代码 | |-- arch 平台相关代码 | |– mips 处理器相关的代码,比如Flush_Cache等
  | |-- cmds pmon shell 命令代码
  | |-- common 各模块共同依赖的代码
  | |-- custom ??这个目录不知道干什么用的
  | |-- dev 一些基本设备的驱动,比如Flash
  | |-- fs 文件系统支持代码
  | |-- loaders 二进制文件加载器代码
  | -- netio 网络命令以及tftp的实现 |-- sys pmon的较低层的代码 | |-- arch 处理器相关代码一些定义 | |– mips
  | | -- include | |-- dev 各种设备的驱动程序 | | |-- ata | | |-- fd | | |-- ic | | |-- microcode | | |– siop
  | | |-- mii
  | | |-- pci
  | | -- u*** | |-- kern 主要是一些系统调用的实现,比如malloc,time, signal, socket | |-- linux | |-- net 实现网络协议 | |-- netinet 实现网络协议 | |-- scsi Scsi协议的实现 | |-- sys 这个大目录的头文件存放区 |– vm ??虚拟内存相关实现
  |-- tools 一些工具
  | |-- bmp_logo 把bmp图转换成C数据的工具
  | |-- bootelf
  | |-- mk
  | |-- pmoncfg 源代码配置工具
  | |-- scripts
  | -- srecord |-- x86emu x86显卡模拟器,主要是运行显卡的BIOS,初始化显卡 |– int10
  | -- x86emu | |-- include | |– x86emu
  | -- src |– x86emu
  | -- x86emu– zloader zip格式加载启动代码
  Targets目录的组成
  每个结构一个目录,我们拿Bonito来为例子,主要有下列文件:
  start.S 位于Targets/Bonito/Bonito 目录下,是C环境建立之前的汇编代码,使整个BIOS运行的起点。
  tgt_machdep.c位于Targets/Bonito/Bonito 目录下,一些板子相关的函数。
  pci_machdep.c进行Targets/Bonito/pci 空间分配的一些函数
  Targets/Bonito/dev 目录下一些板子特殊的设备的驱动。
  Targets/Bonito/conf 目录下是一些编译环境建立需要的一些文件
  参考说明
  本文的撰写过程中,参考了诸多中科龙梦科技有限公司的内部资料(都是可以公开的),另外还有一些未署名的文档,无法一一列举,在此表示感谢。龙芯事业一定会在前仆后继的勇士所铺设的道路上日益壮大!
  +++++++++++++++++++++++++++++++++++++++++
  代码执行流程
  +++++++++++++++++++++++++++++++++++++++++
  当整个板子起电后,CPU将从 0xBFC00000 取指令开始执行,而ROM在系统中的地址就是从该地址开始的。所以,其中的第一条指令就是整个过程中 CPU 要执行的第一个指令。
  初始化CPU内的寄存器,清TLB.
  初始化一些北桥的基本配置,以确保uart能够正常工作。
  初始化uart,主要是设置波特率。
  初始化内存(主要通过I2C协议从内存的EEPROM读取内存参数来进行设置)。
  初始化cache.
  拷贝pmon的代码到内存,然后通过
  la v0, initmips
  jalr v0
  nop
  从此代码便到内存中间去了,从这开始因为可以读写内存,所以有了栈,故可以用C的代码了,所以以后的程序便是C代码了
  +++++++++++++++++++++++++++++++++++++++++
  start.S详解
  +++++++++++++++++++++++++++++++++++++++++
  1
  start.S文件在 /Targets/Bonito/Bonito 目录当中,是整个PMON代码的起点。我们首先研究它。
  文件一开头是版权声明部分,然后是包括一些头文件,然后是一些宏定义,然后才是代码。
  与CPU相关的一些宏定义有
  /*
  Register usage:
  s0 link versus load offset, used to relocate absolute adresses.
  s1 free
  s2 memory size.
  s3 free.
  s4 Bonito base address.
  s5 dbg.
  s6 sdCfg.
  s7 rasave.
  s8 L3 Cache size.
  */
  #define tmpsize s1
  #define msize s2
  #define bonito s4
  #define dbg s5
  #define sdCfg s6
  下面是程序的开头,不过并不生成实际的二进制数据,它告诉编译汇编器一些信息。
  .set noreorder
  .globl _start
  .globl start
  .globl __main
  _start:
  start:
  .globl stack
  stack = start - 0x4000 /* Place PMON stack below PMON start in RAM */
  =====================
  解释:
  .set noreorder
  是告诉汇编汇编器不要对后面的代码进行优化处理,比如重新排列执行代码。
  .globl _start
  .globl start
  .globl __main
  这里,定义了三个全局符号。可以PMON代码中的任何地方引用它。
  _start:
  start:
  .globl stack
  stack = start - 0x4000 /* Place PMON stack below PMON start in RAM */
  在这里定义了子程序的名称 _start 和 start。并定义了堆栈的栈底 stack 值,在 start 以下 16K 处。
  下面是程序执行的第一条语句
  /* NOTE!! Not more that 16 instructions here!!! Right now it’s FULL! /
  mtc0 zero, COP_0_STATUS_REG
  mtc0 zero, COP_0_CAUSE_REG
  li t0, SR_BOOT_EXC_VEC / Exception to Boostrap Location /
  mtc0 t0, COP_0_STATUS_REG
  / SR’s BEV bit is set so the CPU uses the ROM(kseg1) space exception entry point when reboot exception occurs
  la sp, stack
  la gp, _gp
  =====================
  解释:
  由于龙芯的地址空间决定,这里的代码不能超过 16 条指令,因为后面紧跟着的是中断向量的地址。(??)
  接着,就把 CP0 的状态寄存器 COP_0_STATUS_REG 和 COP_0_CAUSE_REG 寄存器全部清空为0。
  li t0, SR_BOOT_EXC_VEC
  接着设置状态寄存器的BEV位,这样就是让 CP0 运行在没有 TLB 的模式,并且一旦发生异常,就进入ROM 的 bfc00000 位置重启。
  后面两句主要设置引导程序的堆栈空间,
  la sp, stack 是把栈底地址给 sp 寄存器,(现在有个疑问就是 pmon的栈是往上还是往下生长的??)
  la gp, _gp 是把编译器中的 _gp 全局地址给 gp 寄存器,这样做法是让全局变量可以作相对寄存器寻址。
  其中_gp是在连接脚本文件里定义的。
  bal uncached
  nop
  bal locate
  nop
  uncached:
  or ra, UNCACHED_MEMORY_ADDR
  j ra
  nop
  =====================
  解释:
  这段程序先进行一个无条件跳转连接指令,这样做的目的很明确就是想清空预取指令和流水线的指令。
  这样就跳到 uncached 这里运行。
  先来看看bal指令会做些什么事情,
  通常bal指令会算出跳转到的目的地址相对于PC寄存器的偏移量,
  然后把PC+8指令地址放到ra寄存器里,也就是把bal locate指令地址放到RA寄存器,以便可以返回。
  由于龙芯2E的加电时启动地址是 0xBFC0 0000,那么放在ra里的值就是 0xBFCO 0028(第8条指令)。
  后面
  or ra, UNCACHED_MEMORY_ADDR,这里进行是与0xA000 00000的或运算,
  也就是说从ROM加载时,不会改变返回地址 ra 的值。
  写这句的目的主要是保证要从ROM中运行后面的一段程序,而不是从其它地址(RAM中)运行。
  所以接着就跳回来到 bal locate位置并执行 bal locate 指令,这样就跳到 locate 的位置执行程序了。
  在MIPS中,异常处理入口有两套,通过 CP0 的 STATUS 寄存器位 BEV 来决定,当 BEV=1 时,异常的入口地址为 0xBFC00000 开始的地址。而 BEV=0,异常地址为 0x80000000 开始的地址,所以PMON程序段开始处是一些异常的调入口,需要跳过这段空间,程序就是通过这个 bal 指令跳到后面的
  2
  下面是那段被跳过去的异常代码
  /*
  Reboot vector usable from outside pmon.
  /
  / started in aligned address by 2^8=256 Bytes, that is 0xbfc00000 + 0x100 = 0xbfc00100 */
  .align 8
  ext_map_and_reboot:
  bal CPU_TLBClear
  nop
  li a0, 0xc0000000
  li a1, 0x40000000
  bal CPU_TLBInit
  nop
  la v0, tgt_reboot
  la v1, start
  subu v0, v1
  lui v1, 0xffc0
  addu v0, v1
  jr v0
  nop
  /*
  Exception vectors here for rom, before we are up and running. Catch
  whatever comes up before we have a fully fledged exception handler.
  /
  / TLB refill exception /
  / bfc00200, this code address is 0xbfc00200, 2^9 = 512 Bytes, it is a exception process function */
  .align 9
  move k0, ra /* save ra */
  la a0, v200_msg
  bal stringserial
  nop
  b exc_common
  .align 7 /* bfc00280 */
  move k0, ra #save ra
  la a0, v280_msg
  bal stringserial
  nop
  b exc_common // print the CP0 register’s infomation
  /* Cache error handler /
  .align 8 / bfc00300 */
  PRINTSTR(“rnPANIC! Unexpected Cache Error exception! ”)
  mfc0 a0, COP_0_CACHE_ERR
  bal hexserial
  nop
  b exc_common
  /* General exception handler /
  .align 7 / bfc00380 */
  move k0, ra #save ra
  la a0, v380_msg
  bal stringserial
  nop
  b exc_common
  .align 8 /* bfc00400 */move k0, ra #save rala a0, v400_msgbal stringserialnop /* when the exception occurs, do this code to present the CP0 register’s content */
  exc_common:
  PRINTSTR(“rnCAUSrnSTATUrnERRORPrnEPrnBADVADDrnRA=”)
  move a0, k0
  bal hexserial
  nop
  // b ext_map_and_reboot
  nop
  /* control the distribution of the code, here we insert a bank 256 Bytes. */.align 8 nop/* handler name table */.align 8.word read.word write.word open.word close.word nullfunction.word printf.word vsprintf.word nullfunction.word nullfunction.word getenv.word nullfunction.word nullfunction.word nullfunction.word nullfunction 3
  
举报

更多回帖

发帖
×
20
完善资料,
赚取积分