一、VMware安装openEuler

1. 镜像下载

镜像下载

2. 虚拟机创建

  • 因为没有vmware没有openEuler选项,所以选择其它Linux。实验要求的镜像版本是20.03,则选择Linux 4.x

    虚拟机创建1虚拟机创建2
  • 性能分配

    image-20240612105458058image-20240612105544825
  • 网络以及其他配置

    image-20240612105810171image-20240612105840696 image-20240612105855440image-20240612105951879
  • 选择映像文件

    image-20240612110317267

3. 启动系统

  • 选择第一个选项install

    image-20240612110852825
  • 图形化界面显示

    image-20240612111032487image-20240612111247092
  • 设置root密码以及创建用户

    image-20240612111358781image-20240612111552188
  • 成功进入系统

    image-20240612112315025
  • 执行 uname -a 指令

    image-20240612112901285

  • 执行 getconf PAGESIZE 指令

    image-20240612112951045

二、安装图形化界面

1. 换源

sudo vi /etc/yum.repos.d/openEuler_x86_64.repo

vi相比vim而言比较原始,但是更常见,在openEuler系统中没有内置vim,所以这里使用vi。

编写清华源:

image-20240612154343401

2. 安装 GNOME

image-20240612155726074

设置gdm开机自启:

sudo systemctl enable gdm.service
sudo systemctl set-default graphical.target
  • 出现的问题:安装完后重启,会遇到 gdm 无法登陆的问题。

    问题解决:这个问题是由于 openEuler 的 gdm 的配置文件不全导致的。具体来说,是 /etc/gdm/Xsession 指向的 /etc/X11/Xsession 不存在。

    我们首先切换到 root 用户,然后从网络上下载并替换该文件即可:

    cd /tmp
    wget https://gitee.com/name1e5s/xsession/raw/master/Xsession
    mv Xsession /etc/gdm/
    chmod 0777 /etc/gdm/Xsession
    

    覆盖文件后,我们输入 reboot 重启,可以看到图形化界面展示如下:

    image-20240612181620851
  • 出现的问题:图形化界面中文乱码。

    image-20240612181746015

    问题解决ctrl+alt+F3切回终端,输入sudo yum -y groupinstall fonts等待下载完成。

    image-20240612194356599

最后使用dnf install gnome-terminal以及yum -y install firefox给当前图形化界面安装终端跟火狐浏览器,就完成了。

image-20240612200158669image-20240612202930709

三、内核的编译安装

1. 系统备份

cd ~
dnf install lrzsz      # rz和sz可以在终端下很方便的传输文件
tar czvf boot_origin.tgz /boot/
sz boot_origin.tgz    # 将备份文件发送到本地
image-20240612204700233

2. 内核源码下载

  1. 下载gitee仓库中的内核压缩文件:

    image-20240612204859139image-20240612205337453
  2. 自动解压后,移动到内核源码目录:

    image-20240612205556819 image-20240612212748493
  3. 清理源代码树:

    image-20240612205728827
  4. 备份文件

    image-20240612210526977
  5. 依赖安装、更改配置:

    yum install ncurses-devel

    image-20240612213027450

    出现的问题:在执行 make menuconfig 命令时缺少了 bison 工具。bison 是一个语法分析器生成器,用于生成解析器代码。make menuconfig 依赖于 bison 来生成配置菜单的相关文件。

    问题解决yum install bison flex安装bison

    image-20240612213917146

    安装编译所需组件:

    yum install elfutils-libelf-devel
    yum install openssl-devel
    yum install bc
    
    image-20240612214742640
  6. 编译安装:

    输入make -j4四核多线程编译:

    image-20240613085859228

    大约半小时后,显示编译完成。

    • 使用make modules_install安装模块

      image-20240613092452339
    • 使用make install安装内核

      image-20240613092809924
    • cd /boot/查看安装的内核,发现新内核已经存在了

      image-20240613164113893
    • 更新引导grub2-mkconfig -o /boot/grub2/grub.cfg

      image-20240613164557815
    • 重启之后,再次使用uname -a可以看到编译成功的新内核如下:

      image-20240613165552757

      下面是旧内核:

      image-20240613165620055

四、内核模块编程

1. 程序编写

  1. 使用C语言编写一个helloworld文件(内核模块)

    image-20240613171643087

    内核模块.c文件的基本框架如下:

    #include<linux/module.h>             //包含了对模块的结构定义以及模块的版本控制
    
    MODULE_LICENSE("GPL");           //声明GPL版权
    static __init module_init(void){      //加载模块
         。。。。。。
    }
    
    static __exit module_exit(void){     //卸载模块
         。。。。。。
    }
    module_init(module_init);
    module_exit(module_exit);
    
  2. 编写Makefile文件

    image-20240613172225839

    Makefile 文件基本框架如下:

    
    ifneq ($(KERNELRELEASE),)                                                
        obj-m :=main.o       //指定将要编译的内核模块列表(一些.o文件)
    
    else
        KERNELDIR ?=/usr/lib/modules/$(shell uname -r)/build      //内核源代码位置
        PWD := $(shell pwd)
    default:
        $(MAKE) -C $(KERNELDIR) M=$(PWD) modules     //编译连接目标
    endif
    .PHONY:clean
    clean:
        -rm *.mod.c *.o *.order *.symvers *.ko
    

2. 编译内核

  1. 输入make指令进行编译

    产生的问题image-20240613172828841

    问题解决:通常是由于Makefile中使用了空格而不是制表符(TAB)作为命令的开头分隔符。在Makefile中,命令行必须以TAB字符开头,而不是空格。

    修改以后成功编译,结果如下:

    image-20240613173215964

    编译后的文件列表如下:

    image-20240613173333602
  2. 内核模块的相关操作:

    • 加载内核模块:insmod

      image-20240613173807393
    • 卸载内核模块:rmmod

      image-20240613174114249
    • 查看内核模块:lsmod

      image-20240613174024823 image-20240613174245022
    • 查看打印信息:dmesg | tail -n 行数

      image-20240613173924697 image-20240613174217268

五、内存管理

1. kmalloc

使用kmalloc分配1KB,8KB的内存,并打印指针地址

  1. 创建kmalloc.c 文件

    image-20240613182307450

    源代码如下:

    #include <linux/module.h>
    #include <linux/slab.h>
    
    MODULE_LICENSE("GPL");
    
    unsigned char *kmallocmem1;
    unsigned char *kmallocmem2;
    
    static int __init mem_module_init(void)
    {
        printk("Start kmalloc!\n");
        kmallocmem1 = (unsigned char*)kmalloc(1024, GFP_KERNEL);
        if (kmallocmem1 != NULL){
            printk(KERN_ALERT "kmallocmem1 addr = %lx\n", (unsigned long)kmallocmem1);
        }else{
            printk("Failed to allocate kmallocmem1!\n");
        }
        kmallocmem2 = (unsigned char *)kmalloc(8192, GFP_KERNEL);
        if (kmallocmem2 != NULL){
            printk(KERN_ALERT "kmallocmem2 addr = %lx\n", (unsigned long)kmallocmem2);
        }else{
            printk("Failed to allocate kmallocmem2!\n");
        }
        return 0;
    }
    
    static void __exit mem_module_exit(void)
    {
        kfree(kmallocmem1);
        kfree(kmallocmem2);
        printk("Exit kmalloc!\n");
    }
    
    module_init(mem_module_init);
    module_exit(mem_module_exit);
    
  2. 创建Makefile 文件

    image-20240613182509119
  3. 编译加载模块

    image-20240613182836871
  4. 查看内存布局

    image-20240613184236383 image-20240613184257505
  5. 得出结论

    在x86_64架构下,虚拟地址空间分为用户空间和内核空间:

    • 用户空间:通常是从 0x00000000000000000x00007fffffffffff
    • 内核空间:通常是从 0xffff8000000000000xffffffffffffffff

    4级页表内存:ffff888000000000 - ffffc87fffffffff (43 bits)

    5级页表内存布局:ffff888000000000 - ffffc87fffffffff (52 bits)

    在这两种布局中,kmalloc 分配的内存地址都位于 ffff888000000000ffffc87fffffffff 这个范围内。这个范围明显高于 0xffff800000000000,属于内核空间。

    因此得出,kmalloc 分配的内存地址位于内核空间

2. vmalloc

使用vmalloc分别分配8KB、1MB、64MB的内存,打印指针地址

  1. 创建vmalloc.c 文件

    image-20240613202726710

    源代码如下:

    #include <linux/module.h>
    #include <linux/vmalloc.h>
    
    MODULE_LICENSE("GPL");
    
    unsigned char *vmallocmem1;
    unsigned char *vmallocmem2;
    unsigned char *vmallocmem3;
    
    static int __init mem_module_init(void)
    {
        printk("Start vmalloc!\n");
        vmallocmem1 = (unsigned char*)vmalloc(8192);
        if (vmallocmem1 != NULL){
            printk("vmallocmem1 addr = %lx\n", (unsigned long)vmallocmem1);
        }else{
            printk("Failed to allocate vmallocmem1!\n");
        }
        vmallocmem2 = (unsigned char*)vmalloc(1048576);
        if (vmallocmem2 != NULL){
            printk("vmallocmem2 addr = %lx\n", (unsigned long)vmallocmem2);
        }else{
            printk("Failed to allocate vmallocmem2!\n");
        }
        vmallocmem3 = (unsigned char*)vmalloc(67108864);
        if (vmallocmem3 != NULL){
            printk("vmallocmem3 addr = %lx\n", (unsigned long)vmallocmem3);
        }else{
            printk("Failed to allocate vmallocmem3!\n");
        }
        return 0;
    }
    
    static void __exit mem_module_exit(void)
    {
        vfree(vmallocmem1);
        vfree(vmallocmem2);
        vfree(vmallocmem3);
        printk("Exit vmalloc!\n");
    }
    
    module_init(mem_module_init);
    module_exit(mem_module_exit);
    
  2. 创建Makefile 文件

    image-20240613204421599
  3. 编译加载模块

    image-20240613204932996
  4. 查看系统页表大小

    image-20240613205901007

    结论:vmalloc 分配的内存地址位于内核空间

六、收获总结

在这次实验中,我通过实际操作openEuler系统,深入体验了内核的编译安装、内核模块的编写以及内存管理的关键技术。这一过程不仅加深了我对操作系统内核工作原理的理解,而且锻炼了我的实践技能和问题解决能力。

内核编译的经历让我对Linux内核的构建过程有了更加直观的认识。从下载源码到配置、编译,再到解决依赖问题和最终的安装,每一步都是对细节的考验,也是对我耐心和解决问题能力的锻炼。特别是在遇到编译错误时,我学会了如何利用系统资源和网络信息来定位并解决问题。在内核模块编程部分,我学习了如何从零开始编写一个简单的内核模块,并通过Makefile进行编译。这个过程让我理解了内核模块与内核之间的交互方式,以及如何在模块中使用printk函数进行调试输出。同时,我也掌握了如何加载和卸载模块,以及如何通过dmesg查看模块的打印信息。内存管理的实验让我对kmalloc和vmalloc这两种内存分配函数有了实际的应用经验。我学习了如何在内核中分配和释放内存,并观察了不同大小内存块的分配情况。这些实验帮助我认识到了内存管理在系统性能和稳定性中的重要性,以及如何避免常见的内存分配错误。

总的来说,这次实验不仅让我获得了宝贵的实践经验,也让我对操作系统的内核有了更深层次的认识。通过亲手操作和解决实际问题,我增强了对复杂技术的理解能力,为将来进一步深入学习操作系统和进行系统级开发打下了坚实的基础。