鉴于越来越多使用者将Linux移植到晶心平台(Andes Embedded)上(AndesCore N12或N10),本文的目的在协助使用者快速、有效率的将Linux 移植到自建的FPGA板子上(CPU是AndesCore 的 N12或N10)。笔者曾协助多家公司工程师进行Linux移植到晶心平台的工作,将Linux移植过程容易遭遇的问题与盲点进行实际说明,期望能对使用者有所帮助,也希望读者不吝指教提供您宝贵的意见。
在进行Linux移植时会发现,使用者的晶心平台可能会有各式各样的组合,除了CPU是使用N12或N10外,使用者对于其他的周边(如RAM,ROM,Timer……)之搭配各有所好,为了有系统性说明Linux移植的要领,将选定一明确的硬件,软件,与开发工具(toolchain)环境做演练说明,除了让读者可以实作明了文中的叙述,当使用者的周边非原设计的硬件(用户自己的IP)时,可以运用移植的基本原则,更改希望移植IP的Linux驱动程序,其他原始码不动,逐一的将使用者的周边驱动程序移植到晶心的平台。
在Linux移植过程中,使用者须建立一基本观念,那就是整个Linux OS可分为两部分,第一部分是与硬件相关的HW dependence code,这部分的程序代码会因对应不同的硬件而造成软件部分需做不同程度的改写;第二部份是与硬件无关的generic code,这部分的程序代码与硬件无关,纯软件运作,不会因平台(Andes, X86, Arm)的改变而有差别。移植Linux的工程师第一步需要能区分出哪一部分程序代码是 HW dependence code,另外部分的程序代码就是generic code,如果在这阶段对程序代码判断错误(HW dependence code/generic code)会拖延Linux移植的进程并增加调试时的困难。
Linux移植到晶心平台过程中,首先须先做到Linux基础架构移植成功。在调试时,Linux的基础架构组件是CPU,timer,interrupt与UART,当CPU与这3项周边移植成功后,scheduler可以运行了,printk也可以运行了Linux系统已经可以正常的运作了。接下来的工作只需将需移植的驱动程序一个一个移植即可,基础骨架移植完成后,调试也有printk可用,接下来只需将肉 (需要加的device drivers) 填上即可。Linux移植比较困难的地方是Linux基础架构尚未完成之前(Linux移植的初期阶段)的调试,所幸晶心提供的标准调试工具与AndeShape?的调试器AICE,可以一步一步找出问题之所在,让初期移植Linux的调试也变得很简单,具体得作法,后文会详细说明。本文叙述重点是如何在晶心平台上建立Linux基础架构,至于个别Linux 驱动程序的移植,坊间有许多的书在介绍,本文就不多加赘述。
1.开发环境与程序
使用者开始进行Linux移植到晶心平台,首先须先选定一版晶心的Linux原始码作为基准再进行软件移植,修改原始码以符合使用者的开发平台,经由工具链的compile与link所产生的Linux的映像文件,再放到FPGA板上以验证程序编写的正确与否,依此开发程序:软件编写->FPGA板验证,再回到软件编写程序直到所有周边IP在FPGA板上验证完全,Linux 移植才完成,如图表 1所示,Linux移植过程中,AICE调试可以有效加快Linux移植的速度。
图表 1 Linux 移植的开发流程
本文选定一组Linux原始码、工具链、FPGA 板和netlist作为晶心的平台(于1.1,1.2,1.3中所述)进行linux的移植。读者可将自己的平台与晶心的平台做类比,从而有效缩短产品开发进程。
1.1 晶心版Linux原始码
目前晶心最新版本的Linux原始码在AndeSoft?的BSP310中,Linux原始码在BSP310套件中的位置为: BSPv310/source/Linux/linux-2.6.tgz.使用BSP310中的ramdisk "xc5_glibc_ramdisk.img"作为filesystem.
1.2 工具链
此晶心平台选用的工具链是AndeSoft?的nds32le-linux-glibc-v2.
1.3 FPGA 板子与 netlist
FPGA板子是晶心AndeShape?的 XC5 开发板。Netlist 为晶心AndesCore?的N10 production version.
移植平台是指使用者要移植Linux的平台,也就是移植Linux的目标平台。将移植平台与晶心平台的比较列表如下: (其中所列之软件皆属于BSP310中之套件)。
图表 2平台与晶心平台的比较表
2.Boot loader
如果使用者有自己惯用的boot loader,可以使用惯用的boot loader以加快开发时程,如果没有boot loader的开发经验,可以选用u-boot作为系统的boot loaderu-boot的source ocde位置在BSPv310/source/Standalone/u-boot/u-boot.tgz.
2.1 U-boot
AndeSoft的BSP310中u-boot source code是需要EBIOS boot up后再执行的u-boot版本。直接boot up不需要其他软件协助的U-boot版本(ROM版)是比较符合使用者的需要,晶心版的u-boot使用方法请参考BSP310 User Manual.如果要ROM版的u-boot需要在BSP310中的u-boot软件做patch,其指令如下:
# patch -p1 patching file arch/nds32/cpu/n1213/ag101/cpu.c
patching file arch/nds32/cpu/n1213/start.S
patching file arch/nds32/include/asm/u-boot-nds32.h
patching file arch/nds32/lib/board.c
patching file board/AndesTech/adp-ag101p/config.mk
patching file include/configs/adp-ag101p.h
patch 完成的u-boot source code 可以产生ROM版的u-boot image,直接开机后的执行结果如图表3所示。
图表 3 u-boot 执行结果图
3. 调试环境
在移植Linux到晶心平台之前,先架设好调试的环境,尤其对底层Linux原始码的移植,有莫大的帮助,在 printk尚未正常运作前,需依靠AndeShape?的AICE与 AndeSoft?的GDB来进行调试。
3.1设定Linux kernel 调试选项
Linux Kernel 需要设定一些调试选项,才能顺利的运用AndeSoft?的GDB进行调试。晶心平台中Linux kernel 调试选项设定如图表4所示,增加这些选项会增加kernel 映像文件的空间,如果空间占用过大以至于不符合设计需求时,可在调试工作完毕后将调试选项关闭以节约不必要的空间浪费。
图表 4设定Kernel hacking 中调试选项勾选
3.2 Linux kernel 调试的程序
Build成kernel bootpImage (含kernel debug message如图表四选项) 后,Linux的映像档放到FPGA板子上,PC host 端的AndeSoft?的GDB透过网络(socket)与AICE连接至FPGA板子,进行调试的工作。
3.2.1. 编译链结成映像档
设定好AndeSoft?的 cross-compiler 路径后,利用下列指令经由compiler and linker后可以得到 bootpImage,指令如下:
#CROSS_COMPILE="nds32le-linux-" ARCH="nds32" make xc5_defconfig
#CROSS_COMPILE="nds32le-linux-" ARCH="nds32" make menuconfig
# CROSS_COMPILE="nds32le-linux-" ARCH="nds32" make bootpImage INITRD=xc5_glibc_ramdisk.img
将生成的bootpIamge放到FPGA板子上,将AICE连接到FPGA板子启动ICEman,指令如下:
#C:\Andestech\AndeSight200MCU\ice>ICEman.exe --p 1234
PC host端的AndeSoft?的GDB透过网络(socket)与AICE连接至FPGA板子,进行调试的工作,示范指令如下:
#ddd --debugger nds32le-linux-gdb vmlinux
gdb>target remote 10.0.2.164:1234
其中IP值 10.0.2.164是一个应用范例,用户可依环境实际IP值进行设定。环境设定完成后,可以开始进行调试工程。
4. 移植Linux至晶心平台关键点经验传承
4.1 Kernel加载程序调试实作
kernel加载程序目的将kernel主程序进行解压缩并加载正确位置,此程序与kernel主程序是两个不同程序,但会一起包在zImage中只是kernel加载程序会attached在zImage的前面。调试时需 file不同的 ELF file才能进行正确的调试工作,kernel加载程序的位置在arch/nds32/boot/compressed/vmlinux,指令如下所示。
#ddd --debugger nds32le-linux-gdb arch/nds32/boot/compressed/vmlinux
kernel主程序的ELF file "vmlinux"在kernel source code的根目录下指令如下所示。
#ddd --debugger nds32le-linux-gdb vmlinux
4.2 Linux kernel 调试实作
kernel加载程序执行完毕后会跳到kernel主程序执行。进入点是arch/nds32/kernel/head.S的assembly code执行完后会进入 kernel 的主要函数 "start_kernel".
4.2.1. RAM offset patch
晶心版Linux原始码搭配XC5平台,RAM的起始位置(指的是PA)是0x0,使用者FPGA开发板的RAM起始位置如果不是0x0,必须要修改FPGA板子中RAM的起始位置,做法是在晶心版的Linux原始码中进行RAM address patch,将原始码中RAM位置调整到FPGA开发板中RAM的真实位置。
4.2.2. PA/VA remap table
当FPGA板子IO的PA设定正确后,使用者需要设定PA/VA remap table,作法可参考arch/nds32/include/asm/spec-ag101.h,依照apec-ag101.h中PA/VA对应的关系去增减使用者自己IO device的 PA/VA remap table.
4.2.3. Kernel 解压缩与software breakpoint
在进行kernel 调试时,如果在低地址处,例如:head.S中进行调试,当设定 software breakpoint时,会有breakpoint无法停下来与AICE 断线的情况发生。原因是当使用者设定software breakpoint时,breakpoint处的instruction会修改并加入break instruction.但kernel解压缩时会将调试的程序代码覆盖造成与GDB调试不一致性而产生错误。解决的方法就是原设定software breakpoint改为hardware breakpoint,这样就可以避免因kernel解压缩所造成调试的错误,降低调试时的困难度。
4.2.4. PA/VA 观念说明与调试要领
在原始码arch/nds32/kernel/head.S中
la $lp, __mmap_switched
mtsr $lp, $IPC
iret
执行完iret后,系统就会从PA转成VA,MMU translation status从translation off转为translation on在此分界处调试规则如下所述,如果观念不清楚及容易产生调试时的错误,请务必牢记。
4.2.4.1. MMU translation off 时期调试
在这个时期调试,VA是不存在的。所有的IO address与memory都是PA没有VA,如果调试地址设成VA,容易hit illegal address 而造成exception.
4.2.4.2. MMU translation on 时期调试
在这个时期调试,PA是不存在的。所有的IO address与memory都是VA没有PA,如果调试地址设成PA,容易hit illegal address 而造成exception.
4.2.5. 移植Linux的基础组件
MMU translation on后,很快就会进入start_kernel 函数,接下来移植的重点就是移植Linux基础组件,那就是interrupt,timer and UART.当这3个device移植成功后,Linux的架构就建立起来了,printk也可以用了,Linux已经可以正常的运作。如果没有意外,可以执行完kernel甚至将filesystem带起来。接下来用户可以将自己的周边组件一个一个的device driver移植入系统。当周边组件移植完成后,Linux系统移植到晶心平台就完成了。
5. 结语
只要能明了熟悉Linux 移植的技巧与重点,使用晶心平台开发Linux的产品将是一件愉快与简单的工作。
评论
查看更多