教程目的:
- 修改RPi上的Linux源碼,增加一個帶參數的系統調用。
教程器材及軟件:
- 樹莓派的板子。
- SD卡(已經有鏡像刷入)。
- 電源線及USB充電器。
- U盤或USB硬盤
- putty和psftp。
- 有DHCP的網線。
教程步驟:
下載源代碼:
mkdir rpi cd rpi git clone git://github.com/raspberrypi/firmware.git PRiFirmware #由於我是換了相同版本的內核,所以這一步是不需要的,以下都將忽略這一步。 git clone git://github.com/raspberrypi/linux.git RpiLinux git clone git://github.com/raspberrypi/tools.git RpiTools
- 然後,就等吧。我這裏下載特別慢,每秒鐘5KB的樣子。然後,就是等了一晚上。
獲取配置文件:
- 登錄到樹莓派上,將/proc/config.gz文件拷貝到家目錄下。
- 查看版本情況:
- 將樹莓派上的SD拔下來,插入到電腦中的SD卡槽中,在rpi文件夾下建一個sd1目錄和sd2目錄。
mkdir sd1 mkdir sd2
- 接着,在/dev目錄下找找sd卡的設備名。將其掛載到sd1和sd2目錄上。
- 到sd2中找到,sd2/home/pi/config.gz文件,將其解壓縮到RpiLinux文件夾中,並將名字改爲.config。
zcat sd2/home/pi/config.gz >RpiLinux/.config
添加一個系統調用:
- 進入到RpiLinux/arch/arm/kernel.
- 新建一個hello.c:
#include <linux/export.h> #include <linux/mm.h> #include <linux/utsname.h> #include <linux/mman.h> #include <linux/reboot.h> #include <linux/prctl.h> #include <linux/highuid.h> #include <linux/fs.h> #include <linux/kmod.h> #include <linux/perf_event.h> #include <linux/resource.h> #include <linux/kernel.h> #include <linux/kexec.h> #include <linux/workqueue.h> #include <linux/capability.h> #include <linux/device.h> #include <linux/key.h> #include <linux/times.h> #include <linux/posix-timers.h> #include <linux/security.h> #include <linux/dcookies.h> #include <linux/suspend.h> #include <linux/tty.h> #include <linux/signal.h> #include <linux/cn_proc.h> #include <linux/getcpu.h> #include <linux/task_io_accounting_ops.h> #include <linux/seccomp.h> #include <linux/cpu.h> #include <linux/personality.h> #include <linux/ptrace.h> #include <linux/fs_struct.h> #include <linux/file.h> #include <linux/mount.h> #include <linux/gfp.h> #include <linux/syscore_ops.h> #include <linux/version.h> #include <linux/ctype.h> #include <linux/compat.h> #include <linux/syscalls.h> #include <linux/kprobes.h> #include <linux/user_namespace.h> #include <linux/kmsg_dump.h> /* Move somewhere else to avoid recompiling? */ #include <generated/utsrelease.h> #include <asm/uaccess.h> #include <asm/io.h> #include <asm/unistd.h> void sys_my_syscall() { printk("Hello World!\n"); }
- 在Makefile中添加hello.o:
- 在call.S中添加223號中斷:
編譯內核:
- 先需要對內核配置一下:
export CCPREFIX=../RpiTools/arm-bcm2708/arm-bcm2708hardfp-linux-gnueabi/bin/arm-bcm2708hardfp-linux-gnueabi- make ARCH=arm CROSS_COMPILE=${CCPREFIX} oldconfig
- 編譯內核:
make ARCH=arm CROSS_COMPILE=${CCPREFIX} -j3
- 上面的-j3表示用3個線程同時進行編譯,你可以增加這個數。一個建議的選擇是cpu核數+1。我的機器比較差,用了30多分鐘,好的機器大約只要15分鐘。
- 編譯完的內核現在還不能用要先處理一下:
cd ../RpiTools/mkimage/ ./imagetool-uncompressed.py ../../RpiLinux/arch/arm/boot/zImage
安裝內核及模塊:
- 將模塊 先安裝到一個臨時的地方:
cd ../.. mkdir modules cd RpiLinux/ make modules_install ARCH=arm CROSS_COMPILE=${CCPREFIX} INSTALL_MOD_PATH=../modules
- 保存原有系統的內核與模塊:
cd ../sd1 sudo mv kernel.img kernel_old.img cd ../sd2 sudo mv /lib/firmware /lib/firmware_old sudo mv /lib/modules /lib/modules_old
- 安裝新的:
cd .. sudo cp RpiTools/mkimage/kernel.img sd1/kernel.img sudo cp -r modules/lib sd2/
測試:
- 將SD卡插回到樹莓派中,啓動。
- 編寫1.c測試:
#define sys_hello() {__asm__ __volatile__ ("swi 0x900000+223\n\t");}while(0) #include <stdio.h> int main(void) { printf("start hello\n"); sys_hello(); printf("end hello\n"); }
- 編譯運行:
後記:
因爲之前搭了一個cygwin的交叉編譯環境,所以想在cygwin下編譯內核。但畢竟只是虛擬的一個環境,還是有很多不一致的地方。第一個現象是特別慢,可能的原因在於cygwin所虛擬的fork比較慢,差不多編譯了兩個小時都沒有完成。第二個遇到的情況是windows是大小寫不敏感的,所以ipt_ECN.c和ipt_ecn.c它會認爲是同名文件。內核中恰巧有這樣的文件,單單大小寫不一樣,這樣就導致編譯內核的時候,會出現錯誤。後來,我通過修改文件名的方法,繞過了這個錯誤。但是,還是出現了其他錯誤,說是logo_linux_clut224.c沒有依賴可以生成它,我看到makefile中有依賴說是只要有logo_linux_clut224.ppm就可以生成它。但是,結果就是make說沒有。然後,這事就進行不下去了。最終,就換到了linux去做。linux下反正很簡單,一步步按教程來就可以了。
參考:
http://aguegu.net/?p=1544
http://elinux.org/RPi_Kernel_Compilation
備註:
此爲浙江大學計算機學院嵌入式系統課程實驗報告。