編譯內(nèi)核&替換內(nèi)核(v5.8)

環(huán)境

宿主機(jī): Ubuntu 20.04

下載的Linux版本: Linux-5.8.1

可以通過(guò) cat /proc/version 或 uname -a 查看宿主機(jī)版本, 然后再選擇對(duì)應(yīng)的版本下載.

v-dev@vdev-VirtualBox:~$ uname -r
5.8.0-63-generic

v-dev@vdev-VirtualBox:~$ ll /usr/src
total 24
drwxr-xr-x  6 root root 4096 8月   1 10:13 ./
drwxr-xr-x 14 root root 4096 4月  23  2020 ../
drwxr-xr-x 24 root root 4096 4月  23  2020 linux-headers-5.4.0-26/
drwxr-xr-x  7 root root 4096 4月  23  2020 linux-headers-5.4.0-26-generic/
drwxr-xr-x  7 root root 4096 8月   1 09:39 linux-headers-5.8.0-63-generic/
drwxr-xr-x 24 root root 4096 8月   1 09:39 linux-hwe-5.8-headers-5.8.0-63/

更新 /etc/apt/sources.list

deb http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-security main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-updates main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-proposed main restricted universe multiverse
deb http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse
deb-src http://mirrors.aliyun.com/ubuntu/ focal-backports main restricted universe multiverse

deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-updates main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-backports main restricted universe multiverse
deb https://mirrors.tuna.tsinghua.edu.cn/ubuntu/ focal-security main restricted universe multiverse


apt-get update
sudo apt-get install build-essential gcc make perl dkms
sudo apt-get install flex
sudo apt-get install bison
sudo apt-get install libncurses5-dev
sudo apt-get install libssl-dev
sudo apt-get install libelf-dev

reboot

編譯內(nèi)核源碼

1.下載內(nèi)核源碼步驟

下載內(nèi)核源碼步驟.png

2.解壓源碼包

如果下載的文件類型是linux-5.8.1.tar.xz則需要兩步解壓

xz -d linux-5.8.1.tar.xz

tar -xvf linux-5.8.1.tar

如果下載的文件類型是linux-5.8.1.tar.gz則只需要一步解壓

tar -xvf linux-5.8.1.tar.gz

3.指定硬件架構(gòu)體系

# export ARCH=x86

4.配置board config

進(jìn)入解壓后的linux-5.8.1目錄執(zhí)行以下命令

# sudo make x86_64_defconfig

結(jié)果如下圖

配置board config.png

5.配置內(nèi)核

繼續(xù)執(zhí)行 sudo make menuconfig命令

配置內(nèi)核.png

6.編譯內(nèi)核

編譯源碼.png

好長(zhǎng)時(shí)間...

內(nèi)核編譯完成

測(cè)試自己寫的字符設(shè)備驅(qū)動(dòng)程序

在linux-5.8.1目錄下創(chuàng)建debug目錄,并創(chuàng)建my_char_device.c和Makefile兩個(gè)文件

并不是說(shuō)這里的my_char_device.c依賴于linux-5.8.1目錄下的文件, 它依賴的是宿主機(jī)的文件. 之所以把它放在linux-5.8.1目錄下, 是后期會(huì)把它編譯到linux-5.8.1內(nèi)核中. 如果你只是為了測(cè)試自己寫的字符設(shè)備驅(qū)動(dòng)程序, my_char_device.c可以任意放置, 甚至也不需要下載和編譯linux-5.8.1

字符設(shè)備驅(qū)動(dòng)源文件 my_char_device.c


#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/uaccess.h>


MODULE_LICENSE("GPL");

static struct class *struct_class;
static int dev_major;

static int open(struct inode *pinode, struct file *pfile)
{
    printk(KERN_WARNING "L%d->%s() major=%d,minor=%d\n", __LINE__, __FUNCTION__, imajor(pinode), iminor(pinode));
    return 0;
}
static ssize_t read(struct file *pfile, char __user *pbuf, size_t count, loff_t *off)
{
    int ret;
    // 用戶態(tài)應(yīng)用程序調(diào)用read方法時(shí)返回這里定義的字符數(shù)組數(shù)據(jù)
    char data[] = "data from my_char_device";
    int len = min(count, sizeof(data));
    ret = copy_to_user(pbuf,data,len);
    printk(KERN_WARNING "L%d->%s()\n", __LINE__, __FUNCTION__);
    return ret;
}
static ssize_t write(struct file *pfile, const char *pbuf, size_t count, loff_t *off)
{
    int ret;
    char data[100];
    int len = min(count, sizeof(data));
    ret = copy_from_user(data,pbuf,len);
    printk(KERN_WARNING "L%d->%s():%s\n", __LINE__, __FUNCTION__, data);
    return count;
}
static int release(struct inode *pinode, struct file *pfile)
{
    printk(KERN_WARNING "L%d->%s()\n", __LINE__, __FUNCTION__);
    return 0;
}


static struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = open,
    .read = read,
    .write = write,
    .release = release,
};


static int my_char_device_init(void)
{
    printk(KERN_INFO "my_char_device init!\n");
    // 查看cat /proc/devices   查看未使用的設(shè)備號(hào)
    // my_char_device 設(shè)備文件名稱
    dev_major = register_chrdev(0, "my_char_device", &fops);
    struct_class = class_create(THIS_MODULE, "my_char_class");
    // 自動(dòng)創(chuàng)建設(shè)備文件     也可以通過(guò) `mknod /dev/my_char_device c 200 2` 手動(dòng)創(chuàng)建設(shè)備文件
    device_create(struct_class, NULL, MKDEV(dev_major, 2), NULL, "my_char_device");
    
    return 0;
}
static void my_char_device_exit(void)
{
    printk(KERN_ALERT "my_char_device exit!\n");
    device_destroy(struct_class, MKDEV(dev_major, 2));
    class_destroy(struct_class);
    unregister_chrdev(dev_major, "my_char_device");
    
}

module_init(my_char_device_init);
module_exit(my_char_device_exit);



Makefile

obj-m := my_char_device.o
KERNEL_DIR := /usr/src/linux-headers-$(shell uname -r)
PWD := $(shell pwd)
default:
    make -C ${KERNEL_DIR} M=${PWD} modules
clean:
    rm -f *.o *.ko *.mod.c *.mod.o modules.* Module.*

image.png

編譯模塊

image.png

插入和卸載模塊

image.png

通過(guò)執(zhí)行dmesg命令查看輸出信息

image.png

插入模塊之后
在/sys/class目錄下會(huì)出現(xiàn)一個(gè)my_char_class目錄.

image.png

在/dev/目錄下會(huì)出現(xiàn)一個(gè)my_char字符設(shè)備文件.


image.png

測(cè)試一下自己寫的字符設(shè)備驅(qū)動(dòng)程序

main.c

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>


int main()
{
    
    int fd;
    char data[100];
    fd = open("/dev/my_char_device", O_RDWR);
    read(fd, data, 100);
    printf("%s\n", data);

    char info[100] = "www.infuq.com";
    write(fd, info, 14);

    return 0;
}

編譯&執(zhí)行


image.png

返回的數(shù)據(jù)data from my_char_device 就是上面驅(qū)動(dòng)程序my_char_device_read方法中定義的數(shù)據(jù).

將自己寫的字符設(shè)備驅(qū)動(dòng)程序編譯到內(nèi)核中

一路走下來(lái), 我們編譯了內(nèi)核, 也寫了自己的驅(qū)動(dòng)程序. 現(xiàn)在就要把自己寫的驅(qū)動(dòng)程序編譯到內(nèi)核中.

1.將我們寫的my_char_device.c文件拷貝到linux-5.8.1/drivers/char目錄下,效果圖如下

因?yàn)槲覀儗懙氖亲址O(shè)備驅(qū)動(dòng),因此必須拷貝到指定的目錄下. 之前寫的Makefile文件不需要拷貝.

image.png

2.編輯Kconfig文件


image.png

添加一項(xiàng)config,如下圖.

image.png

經(jīng)過(guò)上面的配置,在接下來(lái)配置內(nèi)核選項(xiàng)的時(shí)候就可以看到我們添加的選項(xiàng)了

3.編輯Makefile

這里的Makefile是linux-5.8.1/drivers/char目錄下自己的Makefile, 并不是我們上面自己寫的Makefile

image.png

添加如下一行內(nèi)容

image.png

這里的CONFIG_MY_CHAR_DEVICE不能隨便寫. 在上一步編輯Kconfig文件時(shí), 我們添加的一個(gè)選項(xiàng)是config MY_CHAR_DEVICE, 因此這一步就要寫CONFIG_MY_CHAR_DEVICE. 如果上一步我們?cè)O(shè)置的選項(xiàng)是config TMP_DEVICE, 那么這一步就要寫CONFIG_TMP_DEVICE.

3.編譯內(nèi)核

image.png

如上圖, 依次執(zhí)行 export ARCH=x86 , sudo make x86_64_defconfig , sudo make menuconfig 命令.

在執(zhí)行sudo make menuconfig命令會(huì)彈出彈框, 依次選擇 Device Drivers -> Character devices , 最后會(huì)看到如下界面, 就看到了我們自己的字符設(shè)備選項(xiàng), 把它勾選, 那么就會(huì)自動(dòng)編譯到內(nèi)核中了.

image.png

編譯內(nèi)核 sudo make

image.png

如上圖, 的確看到了把我們自己寫的驅(qū)動(dòng)程序編譯到了內(nèi)核中.

替換內(nèi)核

經(jīng)過(guò)上面的步驟, 我們驗(yàn)證了自己寫的字符驅(qū)動(dòng)程序是正確的, 我們也成功的把自己寫的字符驅(qū)動(dòng)程序編譯進(jìn)入了內(nèi)核. 這一次, 我們需要把我們已經(jīng)成功編譯的內(nèi)核版本5.8.1替換掉宿主機(jī)自己的內(nèi)核版本.

1.sudo make modules_install 安裝內(nèi)核模塊

image.png

2.sudo make install 安裝內(nèi)核

image.png

3.修改grub
sudo vi /etc/default/grub


image.png

ubuntu20修改成如上效果, 其他版本請(qǐng)讀者朋友自行解決

4.sudo update-grub

image.png

5.重啟機(jī)器

image.png

如上圖,選擇'Advanced options for Ubuntu'

image.png

如上圖,選擇我們之前編譯的5.8.1版本內(nèi)核進(jìn)行啟動(dòng)

啟動(dòng)之后,查看版本


image.png

查看我們自己的字符驅(qū)動(dòng)是否被加載了


image.png

再次調(diào)用我們之前測(cè)試字符設(shè)備的程序,數(shù)據(jù)也正常返回.


image.png

一路走來(lái), 編譯內(nèi)核 -> 自己寫個(gè)字符設(shè)備驅(qū)動(dòng)程序 -> 把自己寫的字符設(shè)備驅(qū)動(dòng)程序加載進(jìn)內(nèi)核并再次編譯內(nèi)核 -> 替換掉系統(tǒng)自身內(nèi)核,使用我們自己的內(nèi)核.

基于以上, 后面就可以修改一下內(nèi)核數(shù)據(jù), 調(diào)試內(nèi)核, 驗(yàn)證一些結(jié)論就有一些幫助了.

測(cè)試塊驅(qū)動(dòng)

my_disk.c


#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/sched.h>
#include <linux/mount.h>
#include <asm/io.h>
#include <linux/uaccess.h>
#include <mach/devices.h>
#include <mach/soc.h>
#include <mach/platform.h>
#include <linux/miscdevice.h>
#include <linux/delay.h>
#include <linux/genhd.h>
#include <linux/blkdev.h>
#include <linux/hdreg.h>
#include <linux/vmalloc.h>

MODULE_LICENSE("GPL");

#define VDISK_SIZE 10 * 1024 * 1024 // 10M
#define SECTOR_SIZE 512

static int my_disk_major;
static struct gendisk *gdisk;
static spinlock_t lock;
unsigned char *vmem; // 基于內(nèi)存的磁盤,即把內(nèi)存中的某塊區(qū)域當(dāng)成磁盤使用.

static int my_disk_open(struct block_device *dev, fmode_t mod)
{
    return 0;
}
static int my_disk_getgeo(struct block_device *blk, struct hd_geometry *geo)
{
    geo->heads = 4;
    geo->sectors = 16;
    geo->start = 0;
    geo->cylinders = 10 * 1024 * 1024 / 512 /4 /16;
    return 0;
}

static struct block_device_operations my_disk_fops = {
    .owner = THIS_MODULE,
    .open = my_disk_open,
    .getgeo = my_disk_getgeo,
}

static void handle_disk_request(struct request_queue *queue)
{
    struct request *req;
    unsigned int size,off;
    req = blk_fetch_request(queue);
    while (req)
    {
        size = blk_rq_cur_bytes(req);
        off = req->__sector * SECTOR_SIZE;

        if (rq_data_dir(req) == READ)
            memcpy(req->buffer, vmem + off, size);
        else if (rq_data_dir(req) == WRITE)
            memcpy(vmem + off, req->buffer, size);

        if (!__blk_end_request_cur(req, 0))
            req = blk_fetch_request(queue);
    }
}


static int __init my_disk_init(void)
{

    vmem = vmalloc(VDISK_SIZE);
    my_disk_major = register_blkdev(0, "my_disk");
    gdisk = alloc_disk(3);

    gdisk->major = my_disk_major;
    gdisk->first_minor = 1;
    gdisk->fops = &my_disk_fops;
    strcpy(gdisk->disk_name, "my_ram_disk");
    spin_lock_init(&lock);
    gdisk->queue = blk_init_queue(handle_disk_request, &lock);

    set_capacity(gdisk, VDISK_SIZE / SECTOR_SIZE);

    add_disk(gdisk);

    return 0;
}

static void __exit my_disk_exit(void)
{
    del_gendisk(gdisk);
    put_disk(gdisk);
    unregister_blkdev(my_disk_major, "my_disk");
    vfree(vmem);
}



module_init(my_disk_init);
module_exit(my_disk_exit);

編譯busybox

1.下載解壓

下載busybox.png

https://busybox.net/downloads/busybox-1.30.0.tar.bz2

解壓命令tar -xvf busybox-1.30.0.tar.bz2

解壓到與linux-5.8.1目錄同級(jí)

同級(jí)目錄.png

2.配置

配置busybox.png

3.編譯和安裝

編譯和安裝busybox.png

完成之后會(huì)生成一個(gè)_install目錄,進(jìn)入此目錄

_install目錄.png

[x-dev@DESKTOP-EODNRN1 _install]$ mkdir etc dev mnt
[x-dev@DESKTOP-EODNRN1 _install]$ mkdir -p proc sys tmp mnt
[x-dev@DESKTOP-EODNRN1 _install]$ mkdir -p etc/init.d/
[x-dev@DESKTOP-EODNRN1 _install]$ vim etc/fstab
proc        /proc           proc         defaults        0        0
tmpfs       /tmp            tmpfs      defaults        0        0
sysfs       /sys            sysfs        defaults        0        0
[x-dev@DESKTOP-EODNRN1 _install]$ vim etc/init.d/rcS
echo -e "Welcome to tinyLinux"
/bin/mount -a
echo -e "Remounting the root filesystem"
mount  -o  remount,rw  /
mkdir -p /dev/pts
mount -t devpts devpts /dev/pts
echo /sbin/mdev > /proc/sys/kernel/hotplug
mdev -s
[x-dev@DESKTOP-EODNRN1 _install]$ chmod 755 etc/init.d/rcS
[x-dev@DESKTOP-EODNRN1 _install]$ vim etc/inittab
::sysinit:/etc/init.d/rcS
::respawn:-/bin/sh
::askfirst:-/bin/sh
::cttlaltdel:/bin/umount -a -r
[x-dev@DESKTOP-EODNRN1 _install]$ chmod 755 etc/inittab
[x-dev@DESKTOP-EODNRN1 _install]$ cd dev
[x-dev@DESKTOP-EODNRN1 dev]$ sudo mknod console c 5 1
[x-dev@DESKTOP-EODNRN1 dev]$ sudo mknod null c 3 1
[x-dev@DESKTOP-EODNRN1 dev]$ sudo mknod tty1 c 4 1

制作最小的根文件系統(tǒng)

在busybox-1.30.0目錄下執(zhí)行以下命令


rm -rf rootfs.ext3
rm -rf fs
# 制作一個(gè)空鏡像
dd if=/dev/zero of=./rootfs.ext3 bs=1M count=32
# 將鏡像文件格式化成ext3格式
mkfs.ext3 rootfs.ext3
# 創(chuàng)建一個(gè)掛載點(diǎn)目錄
mkdir fs
# 將空鏡像掛載到掛載點(diǎn)
mount -o loop rootfs.ext3 ./fs
# 將根文件系統(tǒng)目錄和文件復(fù)制到掛載點(diǎn)
cp -rf ./_install/* ./fs
umount ./fs
# 將鏡像打包成內(nèi)核可以識(shí)別的格式
gzip --best -c rootfs.ext3 > rootfs.img.gz

啟動(dòng)

apt install qemu-system-x86


$ qemu-system-x86_64 \
  # 內(nèi)核鏡像地址
  -kernel ./linux-4.9.229/arch/x86_64/boot/bzImage  \
  # 根文件系統(tǒng)鏡像地址
  -initrd ./busybox-1.30.0/rootfs.img.gz   \
  -append "root=/dev/ram init=/linuxrc"  \
  -serial file:output.txt
  
  

參考鏈接

https://www.bilibili.com/read/cv11271232

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末采缚,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子报咳,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 212,542評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件艾帐,死亡現(xiàn)場(chǎng)離奇詭異惰瓜,居然都是意外死亡梅桩,警方通過(guò)查閱死者的電腦和手機(jī)塔鳍,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門伯铣,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人轮纫,你說(shuō)我怎么就攤上這事懂傀。” “怎么了蜡感?”我有些...
    開封第一講書人閱讀 158,021評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)恃泪。 經(jīng)常有香客問我郑兴,道長(zhǎng),這世上最難降的妖魔是什么贝乎? 我笑而不...
    開封第一講書人閱讀 56,682評(píng)論 1 284
  • 正文 為了忘掉前任情连,我火速辦了婚禮,結(jié)果婚禮上览效,老公的妹妹穿的比我還像新娘却舀。我一直安慰自己虫几,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評(píng)論 6 386
  • 文/花漫 我一把揭開白布挽拔。 她就那樣靜靜地躺著辆脸,像睡著了一般。 火紅的嫁衣襯著肌膚如雪螃诅。 梳的紋絲不亂的頭發(fā)上啡氢,一...
    開封第一講書人閱讀 49,985評(píng)論 1 291
  • 那天,我揣著相機(jī)與錄音术裸,去河邊找鬼倘是。 笑死,一個(gè)胖子當(dāng)著我的面吹牛袭艺,可吹牛的內(nèi)容都是我干的搀崭。 我是一名探鬼主播,決...
    沈念sama閱讀 39,107評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼猾编,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼瘤睹!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起袍镀,我...
    開封第一講書人閱讀 37,845評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤默蚌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后苇羡,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體绸吸,經(jīng)...
    沈念sama閱讀 44,299評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評(píng)論 2 327
  • 正文 我和宋清朗相戀三年设江,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锦茁。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,747評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡叉存,死狀恐怖码俩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情歼捏,我是刑警寧澤稿存,帶...
    沈念sama閱讀 34,441評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站瞳秽,受9級(jí)特大地震影響瓣履,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜练俐,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評(píng)論 3 317
  • 文/蒙蒙 一袖迎、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦燕锥、人聲如沸辜贵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,828評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)托慨。三九已至,卻和暖如春连霉,著一層夾襖步出監(jiān)牢的瞬間榴芳,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,069評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工跺撼, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留窟感,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,545評(píng)論 2 362
  • 正文 我出身青樓歉井,卻偏偏與公主長(zhǎng)得像柿祈,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子哩至,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容