您的位置:首页 > 运维架构 > Linux

树莓派1代·添加一个linux系统调用·编译内核

2016-06-01 21:59 1031 查看
(可能会有遗漏。请参考文末的参考资料)
一、      实验目的

学习Linux内核的配置和编译;
深入理解Linux系统调用;
理解ARM和x86的CPU模式(系统模式、用户模式等)的不同。
掌握内核模块的编写方法。
 

二、      实验器材

硬件:

PC一台(windows7旗舰版,ubuntu14.04虚拟机)

树莓派1代一块

USB-TTL串口线一根

SD卡一张(树莓派自带)

SD读卡器(笔记本自带)

键鼠套装(USB接口)

显示器一台(带dvi接口)

Hdmi转dvi转接线一根

杜邦线若干

软件:

      Putty

      Win32DiskImager

      Virtual box5.0.14

      Ubuntu 14.04

 

三、      器材连接

1.    连接树莓派与USB-TTL串口线





树莓派

USB-TTL

2

VCC

6

GND

8

RX

10

TX

 

四、      实验步骤及结果

以下实验步骤针对树莓派1代

1.     搭建环境

搭建环境主要包括:

a)     安装virtual box 5.0.14 ,安装ubuntu 14.04 lts

b)     Windosws:下载Win32DiskImager,用以烧录树莓派官方系统

c)      将sd卡挂入linux虚拟机

d)     Ubuntu:下载内核源码,编译工具链

e)     Ubuntu:下载相关依赖库、工具等

想到一种曲线救国方案,可以不把SD卡挂入linux虚拟机。在虚拟机内编译好kernel.img和Modules后,分步导入SD卡。

以下过程我没有实践过,讲道理是可以的。

a)    从虚拟机拖出kernel.img和modules(modules内有软链接,可能要删除后才能拖出来)

b)    将modules放入boot分区。启动树莓派,在树莓派内将modules目录放入正确的位置(启动后,boot分区位置:/boot)

c)     SD卡插回pc,将新的kernel.img放入boot分区。再启动树莓派。

 

1)     安装virtual box 5.0.14 ,安装ubuntu 14.04 lts

a)     linux环境:ubuntu 14.04 lts

b)     实验使用virtual box作为虚拟机。截止本实验报告,官网最新版virtual box安装ubuntu 14.04,再安装增强功能,拖曳文件、共享剪贴板有问题(不排除是我个人问题)。因此,安装稍旧的 virtual box 5.0.14

c)      安装ubuntu后,需要安装增加功能(启动系统后,虚拟机菜单栏“设备”->安装增强功能)

 

2)     下载Win32DiskImager,刷机

a)     下载Wind32DiskImage

b)     下载树莓派镜像:(内核版本 3.18。稍后下载内核源码需要对应)

https://downloads.raspberrypi.org/raspbian/images/raspbian-2015-02-17/

c)      SD卡放入读卡器,使用Wind32DiskImage将镜像刷入。

Windows下只看得见boot一个分区,不影响,直接刷就好。

 

3)     将sd卡挂入linux虚拟机

a)     SD卡插入笔记本读卡器后,虚拟机不能直接像u盘一样挂入sd卡。

b)     VirtualBox挂入SD卡参考:

http://superuser.com/questions/373463/how-to-access-an-sd-card-from-a-virtual-machine

c)      Windows大致步骤:

                        i.         查看SD卡设备号

                      ii.         建立SD卡的文件链接

                     iii.         Virtual box添加SD卡设备

                     iv.         (如果以上步骤不成功,到virtualbox官网下载虚拟机增强工具,貌似叫extension****。在下载virtual box的页面,会有相应增强工具的链接。我之前下过,不知道是否必须)

d)     注意:

                        i.  添加SD卡后,如果取出了SD卡,linux就不能启动了。弹出SD卡也会导致linux崩溃。没有SD卡时,需要将之前添加的SD卡设备删除,才能正常启动linux

                      ii.  添加SD卡后,ubuntu左侧导航会出现两个硬盘图标。点击后查看具体的挂载位置。如过启动linux后,终端里cd这个位置,说找不到路径。点开一次硬盘图标,再cd,就能找到路径了。

                     iii.  我在linux里,对boot分区操作,会导致linux崩溃,猜测是windows和linux共享了boot分区的原因。所以,对boot分区的操作,我是直接在windows下进行的,另一个分区在linux里操作。

 

4)     下载内核源码,编译工具链

a)     下载内核3.18的源码:

wget https://github.com/raspberrypi/linux/archive/rpi-3.18.y.tar.gz

b)     解压:

tar-xzf rpi-3.18.y.tar.gz

c)      建软链接,方便使用:

ln-s linux-rpi-3.18.y/ linux

d)     下载编译工具链(主要是交叉编译所用的gcc):

注意:最好不要把tools放在linux目录里,tools和linux放在同一个目录下就好

gitclone git://github.com/raspberrypi/tools.git

e)     下载相关依赖库、工具等

以下是我安装了,但我也不知道是不是必须安装的:

apt-getinstall lib32z1 lib32ncurses5

apt-getinstall libncurses5-dev

apt-getinstall bc

 

 

2.  复制配置文件config

刷机后,启动一次树莓派,在树莓派上

1)    查看内核版本

Uname –a

内核为3.18,与下载的源代码相同

2)    复制配置文件config.gz,稍后用于编译内核

cp /proc/config.gz /home/pi

 

       关机,取下SD卡,插入pc,打开虚拟机,在ubuntu内:

1)    复制config.gz

cp  /media/my/fe/home/pi/config.gz  /home/my/linux (fe是SD卡根目录分区路径)

2)    解压

zcat config.gz > .config

 

3.  修改系统调用

1)     在linux/arch/arm/kernel中新建sys_mysyscall.c文件,包含新的系统调用处理函数

该系统调用处理函数向系统日志打印”This is the new system call.”



2)     修改linux/arch/arm/kernel中Makefile文件,将sys_mysyscall.o纳入编译进程



3)     修改linux/arch/arm/kernel中calls.S文件,修改系统的中断向量表

修改223号中断



4)     修改linux/include/uapi/asm-generic/unistd.h头文件,将223号调用与某个宏进行关联



5)     修改linux/中的Makefile,修改内核源码的ARCH类型和编译器路径

CROSS_COMPILE为tools目录中编译工具的路径



 

 

4.  编译内核

不做特别说明,都在linux/目录下

1)     查看、修改配置选项

a)     安装字符菜单支持软件包

apt-getinstall libncurses5-dev

b)     查看、修改配置选项

makemenuconfig

不做修改,直接选中exit退出即可

2)     编译内核

编译过程中,如果出现了一堆可选项,一直按enter即可

a)     编译,使用4个线程

make –j4

编译成功后,linux/arch/arm/boot目录下会生成zImage文件,这就是新的内核映像。如果zImage的大小和SD卡boot分区内kernel.img差距过大,编译肯定出了问题,最有可能是配置步骤有问题(比如没有正确导入.config文件)。



b)     使用tools中的工具,处理zImage文件

                        i.  树莓派需要的是另一种格式的镜像文件,不能直接使用zImage(也许可以,我看有些教程是直接将zImage改为kernel.img,我没有试过)

                      ii.  cd/home/my/tools/mkimage

                     iii.  ./imagetool-uncompressed.py../../linux/arch/arm/boot/zImage (这一步如果没有root权限,会提示某某bin文件写入/读取啥啥错误)

                     iv.  成功后会在当前目录下生成一个kernel.img文件,就是新内核。

3)     提取modules

在编译内核的过程中,模块文件也编译出来了,这里把它们提取出来

a)     在linux上层目录,新建目录modules

mkdirmodules

b)     提取modules

cdlinux

makemodules_install INSTALL_MOD_PATH=../modules

 

5.  替换内核

1)     替换kernel.img

boot分区下,(虚拟机下操作boot分区会导致崩溃,建议对boot分区的操作在windows下进行以下操作)

备份kernel.img:kernel.img -> old_kernel.img

将新的kernel.img (tools/mkimage目录下) 放入boot分区

2)     更新内核modules

将提取出的modules/lib目录拷入树莓派根目录下。

cp–r /home/my/modules/lib /media/my/fe

我在这里采用的是复制的方式,建议不要删除原树莓派lib目录下的东西

3)     验证内核

插回SD卡,启动树莓派

uname–a

根据内核版本号和编译时间可知,内核替换成功



 

 

6.  测试新的系统调用

1)     syscall函数

a)     test.c

#include <linux/unistd.h>
#include <sys/syscall.h>
int main()
{
syscall(223);
return 0;
}


b)     编译

直接在树莓派上编译

gcc–o t test.c

c)     测试

./t运行

dmesg| tail 查看日志

日志最后一行由新系统调用打印。系统调用成功 

 

2)     汇编代码

#include <stdio.h>
#define sys_call() {__asm__ __volatile__ ("swi 0x900000+223\n\t");} while(0)
int main(void)
{
sys_call();
return 0;
}


(网上都是这样写的,但我就是不能成功,表示无奈……)

 

7.  编写内核模块

1)     内核模块代码

加载和卸下模块时,向系统日志打印信息

#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/sched.h>

static int __init modl_init(void)
{
printk("Module starts.\n");
return 0;
}

static void __exit modl_exit(void)
{
printk("Module ends.\n");
}

module_init (modl_init)
module_exit (modl_exit)


2)     交叉编译

a)     无法在树莓派上直接编译,原因是,编译内核模块需要用到内核源码。树莓派上,新内核的/lib/modules/3.18.16目录下有编译所需的build和source目录。但是这两个目录是软链接,指向ubuntu内的linux目录。尝试过将linux目录拷入树莓派内,因为种种原因失败了(如果努力,应该还是可以成功的)。最后选择在ubuntu上交叉编译

b)     Makefile文件

CROSS_COMPILE是编译工具路径

obj-m:=modl.o
KDIR=/home/my/linux
PWD=$(shell pwd)
ARGS:=ARCH=arm CROSS_COMPILE=/home/my/tools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi-
default:
make -C $(KDIR) M=$(PWD) $(ARGS) modules
clean:
rm *.o *.ko *.mod.c
.PHONY:clean


c)     编译

生成modl.ko



 

8.  测试内核模块

1)     将编译出的modl.ko拷入树莓派

2)     挂载内核模块

insmodmodl.ko

3)     验证

dmesg| tail

lsmod

内核模块挂载成功

4)     卸下内核模块

rmmodmodl

dmesg| tail

 

参考资料:

1.    http://blog.csdn.net/xdw1985829/article/details/39077611

2.    http://tieba.baidu.com/p/3987137224?pid=74172808781#74172808781

3.    http://www.jianshu.com/p/802e7f6ff9ce

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: