📄 porting-uclinux-to-mips-c.txt
字号:
Porting ucLinux to MIPS
This document describes how to porting ucLinux to MIPS platform. And also describes how
to porting GNU toolchain and uclibc on that platform. The last version of this document can
always be found at www.xiptech.com.
1.About this document
1.1 What this document tells and doesn't tell
1.2 Copyright notice
1.3 The last version of this document
2. General information of uclinux
2.1 Introduction of uclinux
2.2 How about the GNU toolchain and c lib
3. MIPS
3.1 Introduction of MIPS
3.2 MIPS without MMU
4. Porting ucLinux
4.1 ucLinux kernel structure
4.2 Kernel mode and user mode check
4.3 Memory accessing check
4.4 Fork and vfork
4.5 binfmt_flat.c
4.6 Reserve instruction and linux
4.7 Memory page fault handle
5. Porting GNU toolchain
5.1 GNU toolchain and uclinux
5.2 Porting ELF2FLT
5.3 Reserve instructions and toolchain
5.4 Soft floating
6. Porting uclibc
6.1 Introduction of uclibc
6.2 Stack align to 8 bytes
6.3 Pthread
6.4 float-point instruction
7. JIT Simulator
7.1 Introduction
7.2 How to use it?
7.3 Where can I get it?
8. Other issue
8.1 Share lib on uclinux
8.2 PIC or NO-PIC ?
9. Get and build packages
_______________________________________________________________________________
1.About this document
1.1 What this document tells and doesn't tell
这份文档描述了把uclinux、uclibc和GNU 工具链移植到MIPS平台上时要注意的问题,
同时也简要介绍了相关的资料,最后还介绍了一个由Xipos Tech. 提供的 MIPS Simulator。
文档中没有精确地列出我们修改了linux的哪个位置,因为这在我们提供的patch可以
清楚地看到,而且每个版本的linux都有不同。文档中也没有详细介绍MIPS、uclinux的知
识,因为这些知识可以从很多其它文档中得到。
我们假设读者有MIPS和linux kernel的基础,所以有些问题会说得比较简短。不过很
希望读者能够告诉我们哪些地方讲得过于简陋了,哪些地方不清楚,哪些地方有错,让我们
可以在新的版本中更正。
为了便于说明,我们以MIPSR3000 作为例子:
希望这份文档可以帮助读者顺利地把各个版本的uclinux移植到MIPS上。
1.2 Copyright notice
Copyright (c) 2002-2003
Qiu Liming (qiulm@xiptech.com )
Chang Xinlin (zxl@xiptech.com)
Xipos Technology. ( www.xiptech.com )
个人用户可以免费地获得和阅读这份文档。在未经许可的情况下请不要把它用于商业用
途。
1.3 The last version of this document
文档的最新版本请从www.xiptech.com 获取。
2. General information of uclinux
2.1 Introduction of uclinux
在没有MMU(内存管理单元)的机器上,uclinux是最常用的OS之一。它在很大程度
上和标准的linux兼容,但是把应用程序从linux移植到uclinux仍需小心,很容易出现make
很顺利,而跑起来出错的情况。因为uclinux在fork、mmap、stack 大小等方面和linux不同,
会引起一些不易发现的问题。不过考虑到丰富的linux资源,uclinux仍然是 NO MMU 机器
上的最佳选择。在 www.uclinux.org 上可得到 uclinux的最新版本。
Uclinux 已经被移植到很多平台上,标准的发行版中包括了ARM和ColdFire两个版本。
我们在一个项目中遇到了一款NO MMU的MIPS,发现虽然有些公司已经完成了uclinux向
MIPS的移植,但是我们没有找到公开发布的版本,至少没有找到包括kernel、uclibc、toolchain
的完整的包,加上碰到一些特殊的问题,因此我们自己做了所有的移植工作并把它发布出来。
2.2 How about the GNU toolchain and uclibc
uclibc 是 uclinux上的标准c lib,可以在 www.uclib.org 取得。uclibc中已经有MIPS
相关的代码,但是其中有些部分需要修改。
对于GNU toolchain 的“标准部分”,uclinux和linux都可以使用,toolchain中MIPS
相关的部分大体没有问题。但是uclinux支持的flat文件格式需要一个elf2flt的工具来生成,
这个工具没有考虑MIPS的情况,需要移植。
3. MIPS
3.1 Introduction of MIPS
MIPS 是一款通用的RISC CPU,详细的资料可从 www.mips.com 取得。MIPS的其中
一些特点是:
软件直接管理TLB
delay slot
访问不对齐的地址会引发异常
除0不会产生异常
这些特点或多或少会影响OS和Compiler的设计。
3.2 MIPS without MMU
没有MMU的MIPS在内存布局上有点奇特:
(figure1.jpg)
从图中可以看出,如果想kernel mode和user mode同时使用一块连续的RAM,则应该把
RAM放在物理地址的0x40000000;假如RAM接在物理地址的0x00000000开始,则不能
运行user mode的程序,因为user mode不能访问到任何的RAM。本文以RAM放在
0x00000000的情况来说明,因为这种情况要处理的特殊问题要多一些,而且大多数实际的
机器就是这样安排RAM的。
4. Porting ucLinux
4.1 ucLinux kernel structure
这一小节简要地描述一下uclinux kernel的目录架构,以uclinux 2.4.19为例。我们可以
在很多地方取得标准的linux kernel的源代码,通常是一个linux-2.4.19.tar.gz的文件,然后
在 www.uclinux.org 中取得相应版本的patch,uclinux-2.4.19-patch.tar.gz。展开
linux-2.4.19.tar.gz后把uclinux的patch打进去,得到的就是uclinux了。目录中比原来的linux
多了几个目录
mmnommu
arch/armnommu
arch/m68knommu
include/asm-armnommu
include/asm-m68knommu
这些目录存放了NO MMU的特殊代码,对应的MMU 版本的目录在uclinux中就不会起作
用了。另外为了支持flat格式,还增加了fs/binfmt_flat.c。
我们把include/asm-mips复制到include/asm-mipnommu,把arch/mips复制到
arch/mipsnommu,并且修改Makefile相关的部分,接下来就可以开始porting uclinux to MIPS
的旅程了。
4.2 Kernel mode and user mode (scall_o32.c bug?)
linux中有严格的kernel mode和user mode之分,两种mode对资源的访问权限是大不
一样的。但是在uclinux中这种分别就模糊了很多,主要是因为uclinux中没有了对内存访问
的限制,user mode的程序甚至可以直接操作映射到内存空间的IO端口,控制外设。
MIPS的情况更有趣,CPU根本不能进入user mode运行程序(原因见3.2)。但是
linux/uclinux的架构要求有“user mode”,因为signal和schedule都发生在kernel mode返回
user mode的时候。在CPU不进user mode的情况下,OS要有user mode,这看起来有点怪,
是吗?其实OS的user mode和kernel mode只是一种抽象,并不一定要求CPU就一定是两
种mode,Intel x86有4种mode,在linux里就抽象成两种了。所以,我们要让MIPS一直
运行在kernel mode,同时设法在uclinux区分两种mode。
以下为了避免误解,我们把CPU的模式称为user level和kernel level。
Uclinux执行user mode的程序时会经过一系列操作,关键点是 start_thread 这个macro
(include/asm-mipsnommu/processor.h),
#define start_thread(regs, new_pc, new_sp) do { \
/* New thread loses kernel and FPU privileges. */ \
regs->cp0_status = (regs->cp0_status & ~(ST0_CU0|ST0_KSU|ST0_CU1));\
regs->cp0_status = (regs->cp0_status & ~(ST0_CU0|ST0_KSU|ST0_CU1)) | KU_USER;\
regs->cp0_epc = new_pc; \
regs->regs[29] = new_sp; \
current->thread.current_ds = USER_DS; \
} while (0)
start_thread中设置了KU_USER,这就决定了执行每个新的应用程序都会把CPU切换到user
level,只要把这个bit去掉就可以保证MIPS一直工作在kernel level了。
接下来要解决uclinux如何区分两种mode的问题。也就是说当异常发生时,要看看当
前是否在user mode,是则要换堆栈;当异常返回时,看看是否返回到user mode,是则处理
signal和schedule。原来的MIPS linux中用两种方式来判断这一点,一是用CP0_STATUS中
的CU0,二是用CP0_STATUS中的KU_USER。第一种方式在uclinux中可以正常工作,但
第二种就不行了。所以要找出所有利用KU_USER进行判断的地方,统一改成用CU0。具
体涉及到以下文件:
arch/mipsnommu/kernel/entry.S
arch/mipsnommu/kernel/scall_o32.S
include/arch/mipnommu/stackframe.h
include/arch/mipsnommu/ptrace.h
本节最后一个话题是scall_o32.S,这个文件处理system call,并且独立处理异常进入、
返回。但是在异常返回时并没有检查是否返回到user mode就直接处理signal和schedule,
看来作者认为system call一定来自于user mode。如果在kernel mode中system call,是否会
有问题呢?
4.3 Memory accessing check
为了避免user mode的程序在系统调用中传下来不合法的指针,kernel会在使用指针之
前检查它的合法性。其实也就是看看指针是否指向kernel mode的地址,如果是则不合法,
这是保证OS的安全性和健壮性的最基本手段。
在uclinux中,很难区分kernel mode和user mode的地址,因此上述的合法性检查需要
去掉,否则系统就跑不下去了。
首先要修改的是 include/asm-mipsnommu/uaccess.h 中的 __access_ok,绝大多数的合法
性检查都是由它完成的。另外有一些用 assembly 写的函数会直接检查指针,例如
__strncpy_from_user_asm,这些函数就需要单独修改。
4.4 Fork and Vfork
uclinux的一个特点是只支持vfork而不支持fork。 MIPS linux 里有sys_fork和
sys_clone,可以通过sys_clone来实现vfork。为了避免user mode不小心调用了fork,我们
应该把_sys_fork 也改成vfork。这只要修改传给 do_fork的参数就可以实现了。
4.5 binfmt_flat.c
uClinux 使用独特的flat执行文件格式, 加载该种格式的代码在 binfmt_flat.c 中,在
kernel 源代码上打好 uClinux 的 patch 后,可在代码树的fs/下找到该文件。uClinux 发行
版只支持 ARM和68k, 对于mips, 我们还要对 flat 格式文件的连接和加载作一些调整,详
见下面对 elf2flt 的介绍。
4.6 Reserve instruction and linux
MIPS I中有lwr/lwl,swr/swr这种处理不对齐地址的读写的指令,但是并不是每个MIPS
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -