龙芯1C300B开发板Linux系统移植启动调试记录
基础知识学习记录
开发板照片如下:
开发板上有GD25B128CP1G型号的NOR Flash(应该是16M),对于龙芯开发板来说,系统的pmon引导程序就存放在里面;
编译pmon的编译器是mips-elf-gcc
目前,大多数嵌入式交叉编译工具都基于glibc和Linux内核构建的ARCH-linux-(ARCH可以是ppc,mips或mips64)形式的交叉编译器。这种交叉编译器主要针对运行Linux操作系统的机器,它依赖于指定的C语言库glibc,且需要有MMU的支持,使得这种编译器编译出来的目标文件占用较大空间。本文构建的交叉编译工具链采用ARCH-elf-。其特点是:
- 灵活性强,ARCH-elf-*是一个独立的编译体系,不依赖于指定的C语言库glibc,可以使用newlib等其他C语言库,不需要操作系统的支持,可移植到很多CPU结构上。
- 支持基于UCLinux的操作系统,且不需要MMU支持,编译出来的目标文件占空间相对要少。
- 速度比ARCH-linux-*要快。
龙芯1C300B采用的是MIPS指令集架构
MIPS是最早的,最成功的RISC(Reduced Instruction Set Computer)处理器之一
MIPS架构的机顶盒提供了六种交叉编译工具GCC,如下:
· mipsel-linux-gcc
· mipsel-linux-uclibc-gcc
· mipsel-uclibc-gcc
· mips-linux-gcc
· mips-linux-uclibc-gcc
· mips-uclibc-gcc
首先,mips和mipsel的主要区别在于Big Endian(大端)和Little Endian(小端)结构。
- mips对应的是Big Endian;
- mipsel对应的是Little Endian。
其次,要明白uclibc库。
uclibc库是面向嵌入式Linux系统开发优化的C语言库。比GNU C Library更小,但接口兼容,且更易于配置。
uclibc可运行于标准的以及无MMU的Linux系统之上,支持i386、x86、x64、ARM、AVR32、Blackfin、H8300、M68K、MIPS、PowerPC、SuperH、SPARC和V850等处理器下列。
mips-uclibc-gcc表示采用uclibc库进行编译的GCC。
GCC是一套由GNU开发的编译器集,为什么是编辑器集而不是编译器呢?那是因为它不仅支持C语言编译,还支持C++, Ada, Objective C等许多语言,不仅支持X86处理器架构, 还支持ARM, Motorola 68000, Motorola 8800, Atmel AVR, MIPS等处理器架构
GCC内部结构主要由Binutils、gcc-core、Glibc等软件包组成。
- Binutils:它是一组开发工具,包括连接器,汇编器和其他用于目标文件和档案的工具。【这个软件包依赖于不同的目标机的平台。因为不同目标机的指令集是不一样的,比如arm跟x86就不一样】
- gcc-core:顾明之意是GCC的核心部分,这部分是只包含c的编译器及公共部分,而对其他语言【C++、Ada等】的支持包需要另外安装,这也是GCC为何如此强大的重要原因。【它依赖于Binutils,可以参考安装GCC】
- Glibc:包含了主要的c库,这个库提供了基本的例程,用于分配内存,搜索目录,读写文件,字符串处理等等。【这个包GCC编译生成的库,前辈们为了方便大家开发,就把Glibc放到GCC中】
#include <stdio.h>
int main(int argc, char *argv[])
{
printf("Hello Linux!!\n");
return 0;
}
对于上述代码:
gcc编译流程分为四个步骤:预处理、编译、汇编、链接。个人认为预处理和编译主要由gcc-core来完成,汇编和链接主要由Binutils来完成。那么何时用到glibc呢?看到源码中的printf函数没有,这个函数在GCC中是以库函数的形式存在,这个库函数在glibc库中,在stdio.h头文件中被声明。
arm-elf-gcc跟arm-linux-gcc一样,也是是基于ARM目标机的交叉编译软件。但是它们不是同一个交叉编译软件,两者是有区别的,两者区别主要在于使用不同的C库文件。arm-linux-gcc使用GNU的Glibc,而arm-elf-gcc一般使用 uClibc/uC-libc或者使用REDHAT专门为嵌入式系统的开发的C库newlib。Glibc是针对PC开发的,uClibc/uC-libc是与Glibc API兼容的小型化C语言库,实现了Glibc部分功能。
开始准备工作
文章许多内容参考来自孙冬梅老师和石南老师编著的《嵌入式Linux系统设计及应用》(书中存在的一些小错误和一些小坑已经在下面的内容记录中修正了,可对照学习),相关资料和代码可以从书中找到,另外还可以从龙芯开源社区中下载:
https://www.loongnix.cn
在此声明,本文章以记录为主,其中有不足或者有错误的地方欢迎留言交流 如有错误,望大神轻点喷
搭建tftp服务器环境:
安装tftp功能包
apt-get install xinetd
apt-get install tftp-hpa
apt-get install tftpd-hpa
建立传输目录
mkdir /tftproot
获取权限
chmod 777 /tftpboot
修改配置文件
vi /etc/default/tftpd-hpa3
修改内容为:
#/etc/default/tftpd-hpa
TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/tftproot"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="-l -c -s"
重启 tftp 使配置生效
service tftpd-hpa restart
交叉编译环境配置:
下载并解压缩交叉编译工具:
tar zxvf gcc-4.3-ls232.tar.gz -C /opt
在root用户下执行
vi ~/.bashrc
在其末尾添加语句:
export PATH=/opt/gcc-4.3-ls232/bin:$PATH
安装完成后,可在任何目录下执行 mipsel-linux-gcc –v
如果提示 No such file or directory ,使用 which 命令可以找到,环境变量没有问题。原因是计算机上安装的是 64 位的操作系统,但是交叉工具链是 32 位的,出现兼容问题,安装32 位共享库之后,能解决绝大部分兼容性问题。which 及库安装命令如下:
sudo apt-get install libstdc++6:i386
sudo apt-get install lib32z1
然后安装编译pmon所需要的工具
apt-get install bison
apt-get install flex
apt-get install xutils-dev
PMON编译
方法一:百度网盘中资料
从淘宝上找到客服问他们要百度网盘资料,我手中大部分资料来源于此
使用网盘下载的V2版本资料,经过试验完全启动不起来,不知道问题出在哪里,可能是本人技术有限,最终以失败告终;
方法二:Github资料
https://github.com/lshw/loongson1-pmon
下载后解压缩,运行build_ls1b_dev.sh ,在zloader.ls1c文件夹中生成龙芯1B的gzrom.bin
然后从网上购买CH341A编译下载器,将板载NOR Flash芯片拆下后安装到编译器上,方向如下图所示:
然后打开编译器配套上位机,先配置好储存芯片型号等,然后先点击擦除,再点击查空,一切没有问题以后,再导入groom.bin文件,然后点击编程;
注:为了稳妥起见,建议每次刷写的时候都重新打开软件
然后重新安装NOR Flash到开发板上后上电启动,按空格键进入pmon命令行配置界面,否则就会直接寻找内核和加载文件系统启动;
注:智龙开发板有三块储存区域,GD25B128CP1G型号的NOR Flash,K9F1G08UOC型号的NAND Flash和K4S511632D型号的SDRAM,在pmon中要有关于NAND Flash区域的配置,在/Workstation/tools/loongson1-pmon-master/Targets/LS1X/dev目录下的ls1x_nand.c文件中有:
对于宏定义MTDPARTS,在/Workstation/tools/loongson1-pmon-master/Targets/LS1X/conf目录下的ls1c文件中有定义:
使用广州源码包调试:
pmon包编译:loongson1-pmon-lshw.zip --> loongson1-pmon-master
sudo unzip loongson1-pmon-lshw.zip
1:修改/Workstation/tools/loongson1-pmon-master/Targets/LS1X/dev下ls1x_nand.c
进入如下目录
cd /Workstation/tools/pmon/pmon-ls1x-openloongson/tools/pmoncfg
直接编译
make
然后将pmoncfg可执行文件复制到交叉编译工具链的 bin 目录下
cp pmoncfg /opt/gcc-4.3-ls232/bin
进入目录
方法一:
cd /Workstation/tools/pmon/pmon-ls1x-openloongson/zloader.ls1c.openloongson
make cfg all tgt=rom CROSS_COMPILE=mipsel-linux-
就会生成gzrom.bin文件;
方法二:
切换root用户:在终端输入su然后运行build_openloogson.sh脚本,注意需要联网!
./build_openloogson.sh
然后就会生成pmon_openloongson.bin
linux内核编译:openloongsonV3.tar.gz --> linux-3.0.101
解压缩文件:
tar zxvf linux-3.0.101.tar.gz
启动图形化配置界面
make ARCH=mips CROSS_COMPILE=mipsel-linux- menuconfig
源码中已经全部配置好,这里不需要进行任何改动,直接保存退出
进入到/Workstation/tools/linux-3.0.101/arch/mips/loongson1/ls1c文件下ls1c300b_cbiiv0a_board.c
修改nand分区内容如下:要和pmon中的分区保持一致,否则系统启动不了!
保存好后回到linux根目录,编译
make ARCH=mips CROSS_COMPILE=mipsel-linux-
生成内核镜像文件 vmlinux(未压缩)和 vmlinuz(压缩后)
根文件系统编译:
1:配置编译BusyBox
拷贝源码并解压
tar jxvf busybox1.23.0.tar.bz2
cd busybox-1.23.0
运行图形化配置命令
make menuconfig
配置选项简述,其他按默认配置:
Busybox Settings —>
Build Options —>(以下为二选一)
[ * ] Build BusyBox as a static binary (no shared libs)(静态编译)
[ * ] Build shared libbusybox(动态编译)
指定交叉编译器,交叉编译器的绝对路径前缀
(/opt/gcc-4.3-ls232/bin/mipsel-linux-) Cross Compiler prefix
Busybox Library Tuning —>
[ * ] vi-style line editing commands
[ * ] Username completion(文件系统识别 PS1,以命令行提示符)
[ * ] Fancy shell prompts
Miscellaneous Utilities —>
[ ] ubiattach
[ ] ubidetach
[ ] ubimkvol
[ ] ubirmvol
[ ]ubirsvol
[ ] ubiupdatevol
[ ] ionice
配置完后编译
make clean all
make CONFIG_PREFIX=/Workstation/tools/makefs/rootfs/ install
2:创建文件系统目录
cd /Workstation/tools/makefs/rootfs/
mkdir dev home proc tmp var etc lib mnt sys opt root etc/init.d var/log
3:创建系统配置文件
1:etc/inittab 文件
cd /Workstation/tools/makefs/rootfs/
vi etc/inittab
添加内容如下:
::sysinit:/etc/init.d/rc.sysinit //指定系统启动后首先执行的文件
ttyS2::respawn:-/bin/sh //串口终端,串口号 ttyS2 要与启动参数一致
#tty1::respawn:-/bin/sh //用于开发板屏幕终端显示
#Stuff to do when restarting the init process
#::restart:/sbin/init
#Stuff to do before rebooting
::ctrlaltdel:/sbin/reboot //按 Ctrl+Alt+Delete 组合键,重启文件系统
::shutdown:/bin/umount -a –r //当关机时卸载所有文件系统
#::shutdown:/sbin/swapoff –a //保存退出
2:etc/init.d/rc.sysinit 文件
vi etc/init.d/rc.sysinit
添加如下内容:
#!/bin/sh
#Set binary path
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
#Config dev enviornment
mount -t tmpfs -o size=64k,mode=0755 tmpfs /dev
mkdir -p /dev/pts //为 telnetd 创建 pts 目录
mount -t devpts devpts /dev/pts //挂载 pts 目录
#Build console and serial device files
echo "#Build console and serial device files....."
mknod -m 600 /dev/console c 5 1 //建立设备文件
mknod -m 600 /dev/ttyS2 c 4 66 //建立设备文件
#mount all filesystem defined in "/etc/fstab"
echo "#mount all....."
/bin/mount -a
echo "#Starting mdev....."
echo /sbin/mdev > /proc/sys/kernel/hotplug //设置热插拔事件处理程序为 mdev
/sbin/mdev -s //设备节点维护程序 mdev 初始化
#Set ip
ifconfig eth0 123.123.123.110 up
ifconfig lo 127.0.0.1
3:etc/fstab 文件
vi etc/fstab
添加如下内容:
#device mount-point typeoptions dump fsck order
proc /proc proc defaults 0 0
tmpfs /tmp tmpfs defaults 0 0
sysfs /sys sysfs defaults 0 0
tmpfs /dev mdev defaults 0 0
4:etc/profile 文件
vi etc/profile
添加如下内容:
#!/bin/sh
#/etc/profile:system-wide .profile file for the Bourne shells
echo "Processing /etc/profile....."
#set search library path
export LD_LIBRARY_PATH=/lib:/usr/lib
#set user path
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
#Set PS1 modify command prompt
export PS1='[\u@\h:\w]\$'
#Set hostname
/bin/hostname "Loongson"
HOSTNAM=/bin/hostname
export PS1 HOSTNAME
#Set ll aliae
alias ll="ls -l"
echo "Done!"
修改文件权限:
chmod 755 /Workstation/tools/makefs/rootfs/etc/*
chmod 755 /Workstation/tools/makefs/rootfs/etc/init.d/rc.sysinit
然后制作mdev.config
、resolv.config
、group
、passwd
和文件夹hotplug
这些文件内容教程没有给,我是直接从源码中复制出来的;
4:复制库文件:
交叉编译工具的加载器在目录/opt/gcc-4.3-ls232/sysroot/lib/中:librt.so.1、ld.so.1、libc.so.6、libcrypt.so.1、libm.so.6、libdl.so.2、libpthread.so.0、libresolv.so.2。
动态库文件在目录/opt/gcc-4.3-ls232/mipsel-linux/lib/中:libgcc_s.so.1、libstdc++.so.6。
将以上文件复制到根文件系统下的 lib 目录。
使用脚本快速复制所需的基本动态库
vi cplib.sh
添加内容如下:
#!/bin/bash
#copy mipsel-linux lib
libdir=/opt/gcc-4.3-ls232
fsdir=/Workstation/tools/makefs/rootfs/lib
cp -L $libdir/sysroot/lib/librt.so.1 $fsdir
cp -L $libdir/sysroot/lib/ld.so.1 $fsdir
cp -L $libdir/sysroot/lib/libc.so.6 $fsdir
cp -L $libdir/sysroot/lib/libcrypt.so.1 $fsdir
cp -L $libdir/sysroot/lib/libm.so.6 $fsdir
cp -L $libdir/sysroot/lib/libdl.so.2 $fsdir
cp -L $libdir/sysroot/lib/libpthread.so.0 $fsdir
cp -L $libdir/sysroot/lib/libresolv.so.2 $fsdir
cp -L $libdir/mipsel-linux/lib/libgcc_s.so.1 $fsdir
cp -L $libdir/mipsel-linux/lib/libstdc++.so.6 $fsdir
然后添加权限,并运行脚本:
chmod +x cplib.sh
./cplib.sh
为了减少根文件系统的库大小,使用交叉编译工具即 mipsel-linux-strip
的 strip 工具来处
理库文件,把二进制文件中包含的符号表和调试信息删除掉,可有效减少库文件大小。
mipsel-linux-strip rootfs/lib/*so*
5:制作根文件系统镜像
安装镜像文件制作工具,将如下文件拷贝到Linux系统中:
1:安装依赖工具 zlib:
tar zxvf 1.zlib-1.2.8.tar.gz
cd zlib-1.2.8
./configure
make
make install
2:安装制作 cramfs 文件系统镜像文件工具 mkcramfs
tar zxvf 2.cramfs-1.1.tar.gz
cd cramfs-1.1
make
在当前目录下生成 mkcramfs,将其复制到/usr/bin 目录下
cp mkcramfs /usr/bin
3:安装制作 yaffs2 文件系统镜像文件工具 mkyaffs2image
tarzxvf 3.yaffs2-d43e901.tar.gz
cd yaffs2-d43e901/utils
make
在当前目录下生成 mkyaffs2image,将其复制到/usr/bin 目录下
cp mkyaffs2image /usr/bin
4:安装依赖工具 lzo
tar zxvf 4.lzo-2.09.tar.gz
cd lzo-2.09
./configure --build= i686-linux-gnu --prefix=/Workstation/tools/makefs/install
make
make install
5:安装依赖工具 e2fsprogs(也可以用 apt-get installe2fsprogs 安装)
tar zxvf 5.e2fsprogs-1.42.13.tar.gz
cd e2fsprogs-1.42.13
./configure --build= i686-linux-gnu --prefix=/Workstation/tools/makefs/install
make
make install
cd lib/uuid
make install
6:安装 ubifs 文件系统镜像文件制作工具
方法 1:用命令安装 ubifs 文件系统镜像文件制作工具 mkfs.ubifs 和 ubinize:
apt-get install mtd-utils
方法 2:用安装包来安装 ubifs 文件系统镜像文件制作工具:
tar jxvf 6.mtd-utils-1.5.2.tar.bz2
cd mtd-utils-1.5.2
修改 Makefile
vi Makefile
在版本说明“VERSION = 1.5.2”一行后面添加
PREFIX = /Workstation/tools/makefs/install/mtd
DEPEND = /Workstation/tools/makefs/install
ZLIBCPPFLAGS = -I/usr/local/include
ZLIBLDFLAGS = -L/usr/local/lib
LZOCPPFLAGS = -I$(DEPEND)/include
LZOLDFLAGS = -L$(DEPEND)/lib
LDFLAGS += $(ZLIBLDFLAGS) $(LZOLDFLAGS)
CFLAGS ?= -O2 -g $(ZLIBCPPFLAGS) $(LZOCPPFLAGS)
修改 common.mk
vi common.mk
找到并注释掉“PREFIX=/usr”一行
编译安装:
WITHOUT_XATTR=1 make
make install
此处报错:
error1:
error2:
解决办法:
分别安装库:
(1)sudo apt-get install liblzo2-dev
(2)sudo apt-get install uuid-dev
将在安装目录 install/mtd/sbin 下生成的可执行文件 mkfs.ubifs 和 ubinize 复制到/usr/bin目录下
cp install/mtd/sbin/mkfs.ubifs /usr/bin
cp install/mtd/sbin/ubinize /usr/bin
7:制作镜像文件
文件系统有好几类:
7.1 cramfs 文件系统
mkcramfs rootfs/ rootfs-cramfs.img
chmod +r rootfs-cramfs.img
7.2 yaffs2 文件系统
mkyaffs2image rootfs/ rootfs-yaffs2.img
chmod +r rootfs-yaffs2.img
7.3 ubifs 文件系统
mkfs.ubifs -r rootfs -m 2048 -e 129024 -c 370 -o ubifs.img
通过此命令制作出的 UBIFS 文件系统镜像可在 u-boot 下使用“ubiwrite”命令烧写到NANDFlash 上
新建配置文件 ubinize.cfg,添加内容如下:
[ubifs]
mode=ubi
image=ubifs.img
vol_id=0
vol_size=45MiB
vol_type=dynamic
vol_alignment=1
vol_name=rootfs
vol_flags=autoresize
ubinize -o ubi.img-m 2048 -p 128KiB-s 2048 -O 2048 ubinize.cfg
通过此命令生成的ubi.img
可直接使用 NANDFlash 的烧写命令烧写到 Flash 上
linux系统启动:
将编译生成的gzrom.bin
和vmlinuz
和rootfs-yaffs2.img
放到 /tftproot 文件夹中
将pmon下载到NOR Flash中后启动进入pmon界面
通过set ifconfig syn0 123.123.123.110
配置开发板IP
然后先ping 123.123.123.123测试一下与ubuntu主机是否能通,确认无误后输入如下命令
mtd_erase /dev/mtd0 //擦除数据
mtd_erase /dev/mtd1 //擦除 nand 的第 2 个分区数据
mtd_erase /dev/mtd2 //擦除 nand 的第 3 个分区数据
devcp tftp://123.123.123.123/gzrom.bin /dev/mtd0 //下载pmon到 nand 的第 0 个分区
devcp tftp://123.123.123.123/vmlinuz /dev/mtd1 //下载内核到 nand 的第 1 个分区
set al /dev/mtd1 //设置启动参数,自动从 nandflash 的 mtd1 分区 load 内存,设置在一上电时自动执行 load 内核到内存操作
devcp tftp://123.123.123.123/rootfs-yaffs2.img /dev/mtd2 yaf nw //烧写根文件系统到 nand 的第 3 个分区
set append " root=/dev/mtdblock2" //根目录位置,块设备
set append " $append console=ttyS2,115200" //设置串口 2,115200 波特率
set append " $append noinitrd init=/linuxrc rw rootfstype=yaffs2" //没有使用ramdisk;设置内核启动起
来后进入系统中运行的第一个脚本;指明文件系统类型为 yaffs2
reboot //重启系统
执行过程如下图所示:
然后就可以正常进入系统了
调试失败案例:
使用网上GitHub上下载的最新pmon和linux内核,pmon软件包生成的.bin文件烧录到开发板中能正常启动,但是linux内核编译时会报错
内核编译报错:
Cannot use CONFIG_CC_STACKPROTECTOR_STRONG: -fstack-protector-strong not supported by compiler
网上说这是内核防止堆栈溢出的布丁
使用命令行scripts/config --disable CC_STACKPROTECTOR_STRONG
虽然能继续编译了,但是错误还在,而且最后还是会报错,新的错误是:
一头雾水后决定放弃,网上说还有可能是编译器版本的问题,在GitHub上没有看到关于最新版pmon和内核所使用的gcc和g++编译器的版本,故也知道该使用何种版本,立即推,放弃!
该问题已解决:
猜测可能是gcc编译器版本选错了,在编译pmon时候,运行./build_openloogson.sh时会安装3.4.6-2f版本的gcc
如果使用广东刘工的源码,不改nand.c的情况下,启动开发板不会进入linux系统
修改pmon-ls1x-openloongson/Targets/LS1X/dev/ls1x_nand.c
文件中
#if defined(LS1CSOC)
add_mtd_device(ls1x_mtd, 0, 1024*1024, "bootloader");
add_mtd_device(ls1x_mtd, 1024*1024, 13*1024*1024, "kernel");
add_mtd_device(ls1x_mtd, 14*1024*1024, 50*1024*1024, "rootfs");
add_mtd_device(ls1x_mtd, (50+14)*1024*1024, 64*1024*1024, "data");
重新编译后如下:
广州刘工编译后正常能进入linux的代码NAND分区如下:
在pmon模式下配置tftp环境:
ifconfig syn0 123.123.123.110
至此有关龙芯1C300B开发板Linux系统移植启动调试记录的内容就全部结束了,前前后后也是花了不少时间才完成了,只能说对于国产开发板的道路还是有很长一些路要走,生态和配套资料都无形中增加了入门的难度,但是还是希望想学习的小伙伴们能坚持下,也许我的一点经验就能帮到后面开发的人,与君共勉!