📄 porting-uclinux-to-mips-c.txt
字号:
CPU产品都包含它们,当碰到这种指令时CPU会产生Reserve Instruction 异常 。通常的解
决方法是在kernel 中的 do_ri 里仿真执行指令,但是这并不是最好的方法,先不谈由此带
来的SMP等问题,至少在效率上就是很差的。例如memcpy这个函数里,很可能就包含了
这种指令,如果每条指令都由do_ri来处理,系统的性能就会急剧下降。因此我们必须针对
这些部分作修改。
如果lwl/lwr 指令是在汇编语言里直接使用的(绝大多数是这种情况),那么直接修改代码
就可以了。但是有些“非法指令”是由 gcc 产生的,那就必须修改 gcc了。事实上有些方
案提供者并没有把gcc一并修改,这便给系统留下了一些性能隐患。
4.7 Memory page fault handle
当缺页异常发生时,linux会尝试去查找相应的VMA,并把页补上。这在uclinux中是
不必要的,因此我们可以把这部分代码去掉。
5. Porting GNU toolchain
5.1 GNU toolchain and uclinux (ELF2FLT!!)
如前所述,GNU toolchain 基本可以直接用于uclinux,主要的工作是移植elf2flt,并且
针对目标机器作一些调整。
Erik Andersen (andersen@uclibc.org) 为编译基于 uClibc 的GNU toolchain 编写了两个
Makefile, 分别支持2.95和3.2 两个版本的gcc,可以完成source code download、配置、
编译和安装一系列工作,非常方便,该Makefile 可以从 www.uclibc.org 下载。我们的移植
工作也是在此基础上进行的。
5.2 Porting ELF2FLT
uClinux 使用的flat 执行文件格式,GNU bfd 库并不支持,在uClinux 的应用程序编译过
程中,GNU 工具链以ELF 为目标文件格式,最终由程序 elf2flt 转换为 flat 格式。
首先简单介绍一下 flat 格式文件的连接和加载机制。
一个flat 格式文件由五部分组成,分别为 文件头,text 段,data 段,bss 段,重定位表。
文件头纪录该flat 文件的基本信息,供Loader 使用,主要包括:text、data、bss和重
定位表的大小以及在文件中的位置,执行入口位置,数据压缩方式等等。
text data bass 段为程序的代码和数据,由ld 按照脚本 elf2flt.ld 进行连接得到。
重定位表包含若干32bit 重定位项,与 linux 不同,没有MMU 的 uClinux 不能保证
把程序加载到连接地址上,作重定位是必须的。重定位表只需包括32bit重定位类型。
此外,脚本elf2flt.ld 在 data 段的开始处放置 got 表,这是由于elf2flt 借用了share
library 的浮动代码(PIC)机制,这样可以避免在代码段作重定位,简化了加载过程。Got 表以
一个32bit 的-1 项表示结束。
编译并install elf2flt 后,GNU 工具链中的ld 被脚本ld-elf2flt替代,原ld 改名为
mipsel-uclibc-ld.read。可以这样build 出一个flat 格式的执行文件:
mipsel-uclibc-gcc –Wl,-elf2flt foo.c –o foo
gcc 在编译foo.c 后,调用 ld 进行连接,此时脚本ld-elf2flt(已经改名为 mipsel-uclibc-ld)
会调用两次原来的 ld, 生成 foo.elf 和foo.gdb 两个elf 格式的临时文件,不同之处是foo.elf
是目标文件(.o),包含重定位信息,foo.gdb 是执行文件,包含 got 表。然后,ld-elf2flt 以
这两个文件为参数执行elf2flt。
elf2flt 将从foo.elf 中读取重定位项,对foo.gdb 作重定位并记入重定位表,需要注意
的是由于GOT 表的存在,elf2flt 需要对重定位项的地址作一些调整,将其加上GOT 表的
大小,才能适合foo.gdb。
flat 格式文件的加载由 kernel 中fs/binfmty_flat.c 的代码完成。在读取文件并解压数据
后,要根据加载地址分别对GOT 表项和重定位表项作重定位处理。
对于elf2flt 移植到mips, 只需增加对MIPS 体系的R_MIPS_32重定位的处理就可以了。
但目前的flat机制实现在mips 体系下暴露了一些问题,主要有:
got size 计算:elf2flt计算got size 以调整重定位地址,原始的计算方法只有在data 段所
有section 都对齐到4字节时才能确保正确,在mips 体系下不能保证这一点,我们修改了
计算方法。
base address:elf2flt.ld 以0为基址进行连接,为了支持c++并避免在got 项中出现0值,
我们修改基址为0x40000, 这需要elftflt.ld elf2flt.c 和binfmt_flat.c 同步改动。
5.3 Reserve instructions and toolchain
如4.6节所述,有的情况下我们需要修改 GNU toolchain 来配合特殊的系统。如果系统
只是缺了不对齐内存访问指令,不改toolchain可能还可以勉强过得去,但是有些MIPS CPU
连 mul/div/mod 指令都没有,这时修改toolchain就是必需的了。如何修改toolchain是个不
小的题目,只能在我们其它的文档中再加以详述了。大家也可以参考那篇著名的“GNU
Compiler Collection (GCC) Internals”。
针对不对齐内存访问指令的情况,有个权宜之计,修改gas中的tc-mips.c,也可以避免
编译出非法指令。这样改产生的代码效率不如改gcc高,但是已经比依靠异常处理好很多了。
5.4 Soft floating
无需作其它工作,配置后的gcc 支持软浮点,使用的是gcc 自带的浮点库
(config/fp-bit.c)。编译时只须带 –msoft-float 参数即可, 如: mipsel-uclibc-gcc –msoft-float –c
test.c –o test.o
6. Porting uclibc
6.1 Introduction of uclibc
uClibc(www.uclibc.org) 是为嵌入式系统开发的标准C 库,与glibc 高度兼容,uClibc 专门考
虑了对无MMU 系统的支持,在uClinux 上是当然的选择。uClibc 已经相当成熟,配置和编译也很
容易,只需作很少的调整,即可运行在 mips 体系上。
6.2 Stack align to 8 bytes
gcc 工作在mips 体系上时,如果栈指针没有对齐在 8字节边界,va_arg宏将不能正确拆
解出 8字节长的参数。由于我们的移植支持64bits 浮点数,因此在uClibc 的启动代码中,
我们在调用 __uClibc_main() 之前调整了栈指针。
6.3 Pthread
出于效率的考虑,uClibc 在pthread 的同步支持函数testandset()中使用了MIPS ISA 2
指令进行原子操作,对于嵌入式系统常用的一些 MIPS ISA1 的MPU, 必须修改此处代码。
我们完成了sysmips(MIPS_ATOMIC_SET…) 系统调用并用其实现 testandset()。
6.4 float-point instruction
uClibc (version 0.9.15) 在 setjmp() & longjmp() 的mips实现中,无条件地对浮点寄存器
进行了保存/恢复操作,嵌入式处理器常常没有浮点处理器,应当去除这些指令,编辑文件
libc/linux/mips/__longjmp.c 和 libc/linux/mips/setjmp_aux.c,删除相关代码即可。
7. JIT Simulator
7.1 Introduction
如果你希望熟悉uclinux,或者希望多点了解MIPS,其中一个好办法是亲自做一遍移植
的全过程。把kernel、uclibc、GNU toolchain都建立起来,然后加上 busybox和GUI (例
如micro window)。最好把网络相关的东西也放到系统中,pppd、httpd … 总之把一些基本
的东西做一遍,这样就可以初步掌握uclinux和MIPS了。
但是不是每个人都能拥有一块开发板来做试验,即使有,每次download、烧录的过程
可能也很麻烦。我们为大家提供了一个模拟器(或者说虚拟机)可以解决这个问题。 模拟
器仿真了一个MIPS的CPU,还有外围的中断控制器、flash rom、串口、RTC、LCD等设备,
可以直接运行MIPS GCC生成的binary code,包括linux kernel和所有应用程序。 和其它的
模拟器相比,我们的模拟器最大的特点就是速度快,MIPS CPU的仿真速度在一台P3 650
的PC上可以达到50 mips 以上。我们在模拟器中采用了JIT compile的技术,把MIPS的代
码编译成 x86代码来运行。在高速的PC机上执行模拟器可以流畅地运行flash player这类
动画软件。
我们的模拟器可以用于开发、调试、培训、演示产品等等,但是这次提供的版本只是为
了让有需要的个人学习uclinux和MIPS,所以很多功能并不包含在其中,例如高级调试、
外设扩展等等。而且未经许可请不要将之用于商业活动。
7.2 How to use it?
我们这次提供的版本可以运行在MS windows 98/Me/2000/XP 上(如需linux的版本请
和我们联系)。下载模拟器的包展开后会看到一份详细的使用说明。简单来说,使用者需要
自己建立一个OS kernel image,然后交给模拟器运行就可以了,就像使用开发板一样。
我们提供的uclinux patch中有一个目录,arch/mipsnommu/mach-xipos,里面包含了模拟
器仿真的外围设备的驱动程序。外围设备基本上是以Toshiba 的tx3911为基础的,模拟器
的文档里包含了这方面的信息。
7.3 Where can I get it?
www.xiptech.com
8. Other issue
8.1 Share lib on uclinux
用是否有process independend data来区分,share lib可以分成两种:yes or no。像linux、
Windows 95等OS的share lib的data都是进程独立的,例如errno就是每个进程一个,互不
干扰。而像windows 3.1的share lib中的数据,就是share的。在没有mmu的机器上,实现
后者(share data)是很容易并且自然的,而要实现前者就要花一些功夫了。uclinux就是因
为这个原因而长期没有share lib。不幸的是如果要想利用现有的open source资源,必须实现
process independend data。前一段时间有两家公司分别实现了arm和coldfire下的uclinux的
share lib,还在国外的论坛上引起了很大的回响,虽说用起来有些限制,但好歹也算是有了。
我们为MIPS uclinux 实现了share lib,其中涉及到 gcc、ld、uclinux kernel 的等方面的
修改。但是由于我们刚刚才实现这个功能,未经过测试,因此没有包含在这次发布的patch
中。
8.2 PIC or NO-PIC ?
标准linux中是一定使用PIC code的,因为这是share lib的基础。但是在uclinux却可
以考虑使用 NO PIC code,带来的好处是显然的:运行速度加快。据我们的测试,NO PIC code
大概比PIC code快 30%左右。但是NO PIC code也带来两个缺点:可执行文件变大和加载
可执行文件的速度变慢。原因是显然的,PIC code只需要针对GOT table和init data作重定
位,而NO PIC code要做的重定位的项数则要多得多。在实际中,我们可以根据需要来决定
用哪一种。
顺便一提,我们提供的elf2flt中暂时还没有处理NO PIC code的情况。
9. Get and build packages
Build 工具链
首先你要联接到 Internet,.从 www.xipos.com 下载 toolchain.tar.gz. 解压缩后 make 即可,
Make 过程download 需要的源代码并配置编译.
缺省情况下,工具链安装在 /opt/toolchain, 使用时需要:
export PATH=/opt/toolchain/bin:$PATH
如果要更改这个路径, 在 make 之前编辑 Makefile, 修改其中的TARGET_PATH.
Make 过程中download 下来的 uClibc 可能需要作一些改动,如去除浮点指令等。这可
以在编译完工具链后随时进行。完成对源代码修改后,
make uclibc
即可,make 过程会安装重新编译后的uClibc.
或者,你也可以从 www.xiptech.com 下载 uClibc 0.9.15 的patch, 然后:
cd build/uClibc-uClibc-0.9.15
patch -p1 < <path>/uClibc-0.9.15-mipsnommu.patch
cd ../..
make uclibc
toolchain.tar.gz 是 Erik Andersen 为方便配置基于uClibc的开发环境写的,我们只对其中
的Makefile 作了少许修改,并使用了我们为mips 修改过的elf2flt。 这个包本身还在不断
更新。访问 www.uclibc.org 可以得到最新版本。
Build uclinux
下载源代码:
下载 linux-2.4.19.tar.bz2
http://www.kernel.org/pub/linux/kernel/v2.4/linux-2.4.19.tar.bz2
下载 uClinux-2.4.19-uc1.diff.gz
http://www.uclinux.org/pub/uClinux/uClinux-2.4.x/uClinux-2.4.19-uc1.diff.gz
下载 uClinux-2.4.19-uc1-mips.diff.gz
http://www.xiptech.com/download/uClinux-2.4.19-uc1-mips.diff.gz
下载 Romfs 文件
http://www.xiptech.com/download/romfs.tar.gz
解开源代码:
mkdir mips-uclinux
cd mips-uclinux
bunzip2 < ../linux-2.4.19.tar.gz2 | tar xvf -
gunzip ../uClinux-2.4.19-uc1.diff.gz
gunzip ../uClinux-2.4.19-uc1-mips.diff.gz
tar zxvf ../romfs.tar.gz
cd linux-2.4.19
patch -p1 < ../uClinux-2.4.19-uc1.diff
patch -p1 < ../uClinux-2.4.19-uc1-mips.diff
编译 Kernel
make mrproper
cp xipos.config .config
make menuconfig
make dep
make
Kernel 编译后,生成文件 uclinux.bin,其中包含Kernel 二进制码和作为root 的romfs 映像,
使用模拟器运行uclinux.bin.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -