操作系统OpenEuler实验 实验内容与环境 实验内容 完成openEuler操作系统的安装,完成内核更新,在此基础上,增加完成其他功能。本次实验已增添完成:内核模块编程、内存管理、内核时间管理。
实验环境 虚拟机Vmware和openEuler操作系统。
实验过程 openEuler操作系统安装 1.下载OpenEular镜像
2.安装到虚拟机
(1)新建虚拟机
(2)进入虚拟机,开始安装
①等待安装检查
②进行语言设置:选择中文
③进行软件选择:这里我们选择最小安装,附加选项为标准和开发工具
④设置ROOT密码:12Lhl0408
⑤创建用户:设置用户名为buptoslihaolun2023211595
设置密码为123456@Lhl04,这里我设置了不需要密码即可登录账户
⑥安装完成:进行重启
⑦随后进入系统。
⑧输入刚刚设置的账号密码进行登录
(3)执行相应指令
①执行uname -a指令
②执行getconf PAGESIZE指令,查看openEuler的分页大小,为4096
(4)安装桌面环境(gnome)以及terminal
①配置清华源
先输入以下指令打开配置文件
1 vim /etc/yum.repos.d/openEuler_x86_64.repo
打开后按下键盘i键进入编辑模式,添加以下内容。添加完成后按下esc结束编辑模式。输入:wq!保存并退出。
#添加如下内容
1 2 3 4 5 6 \[osrepo\] name=osrepo baseurl=https://mirrors.tuna.tsinghua.edu.cn/openeuler/openEuler-20.03-LTS/OS/x86_64/ enabled=1 gpgcheck=1 gpgkey=https://mirrors.tuna.tsinghua.edu.cn/openeuler/openEuler-20.03-LTS/OS/x86_64/RPM-GPG-KEY-openEuler
②安装gnome、terminal
1 dnf install gnome-shell gdm gnome-session
1 dnf install gnome-terminal
1 2 3 systemctl enable gdm.service systemctl set-default graphical.target
1 2 3 4 5 cd /tmpwget https://gitee.com/name1e5s/xsession/raw/master/Xsession mv Xsession /etc/gdm/chmod 0777 /etc/gdm/Xsession
③gnome 桌面安装成功
(4)执行uname -a指令、getconf PAGESIZE指令
1 2 uname -agetconf PAGESIZE
(5)安装Firefox
内核更新 1.系统备份
1 2 3 4 cd ~dnf install lrzsz tar czvf boot_origin.tgz /boot/ sz boot_origin.tgz
2.内核源码下载
(1)在gitee仓库中下载openEuler内核压缩文件
(2)解压缩至/usr/src/kernels
移动文件指令:
1 sudo mv /home/buptoslihaolun2023211595/Downloads/kernel-4.19.90-2405.5.0 /usr/src/kernels/
3.清理代码树:进入解压好的源码文件夹执行命令,清理过去内核编译产生的文件。
4.生成内核配置文件.config
(1)先将将系统原配置文件拷贝过来
1 cp /boot/config-4.19.90-2003.4.0.0036.oe1.x86_64 /usr/src/kernels/kernel-4.19.90-2405.5.0
(2)执行依赖安装
1 yum install ncurses-devel
(3)对配置进行需要的更改:我没有进行改动,直接默认配置,然后选择Save,生成了一个.config文件。
5.内核编译及安装
(1)安装所需组件
1 2 3 yum install elfutils-libelf-devel yum install openssl-devel yum install bc
(2)开始编译
①时间很长,大约3~4小时,需要耐心等待。
②编译完成
(3)安装模块
(4)安装内核
(5)在/boot目录下查看新安装的内核
6.更新引导
(1)下面的命令会根据/boot/目录下的内核文件自动更新启动引导文件
1 grub2-mkconfig -o /boot/grub2/grub.cfg
(2)重启,选择第二个,这是我们新安装的内核
7.修改默认启动内核
(1)查看当前系统所有可用内核
1 cat /boot/grub2/grub.cfg |grep "menuentry "
(2)查看当前默认启动内核
(3)修改默认启动内核,输入后再次查看内核版本,发现已经更新为新内核,原内核为4.19.90-2003,新内核为4.19.90
1 grub2-set-default 4.19.90
(4)执行uname -a指令
至此,实验步骤完成。
内核模块编程 1.尝试先编写hello world,先编辑c文件
2.此时还需要一个Makefile文件
3.准备运行,运行成功
4.查看编译后文件列表
5.执行相关命令。
①加载内核模块:insmod
②查看打印信息:dmesg | tail -n 行数
③查看内核模块:lsmod
④卸载内核模块:rmmod
实验完成。
内存管理 1.使用kmalloc分配1KB,8KB的内存,并打印指针地址
(1)创建kmalloc.c和Makefile文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #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);
1 2 3 4 5 6 7 8 9 10 11 ifneq ($(KERNELRELEASE) ,) obj-m := kmalloc.o else KERNELDIR ?=/usr/src/kernels/kernel-4.19.90-2405.5.0 PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif .PHONY :cleanclean: -rm *.mod.c *.o *.order *.symvers *.ko
(2)编译、加载模块。依次输入以下命令进行实验。
(3)查看内存布局
打开/usr/src/kernels/kernel-4.19.90-2405.5.0/Documentation/x86/x86_64/ mm.txt文件。
(4)结果分析:由运行结果可知,kmalloc分配的内存地址,位于内核空间。
2.使用vmalloc分别分配8KB、1MB、64MB 的内存,打印指针地址
(1)创建vmalloc.c和Makefile文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #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);
1 2 3 4 5 6 7 8 9 10 11 ifneq ($(KERNELRELEASE) ,) obj-m := vmalloc.o else KERNELDIR ?= /usr/src/kernels/kernel-4.19.90-2405.5.0 PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif .PHONY :cleanclean: -rm *.mod.c *.o *.order *.symvers *.ko
(2)编译、加载模块。依次输入以下命令进行实验。
(3)查看内存布局
打开/usr/src/kernels/kernel-4.19.90-2405.5.0/Documentation/x86/x86_64/ mm.txt文件。
(4)结果分析:由运行结果可知,vmalloc分配的内存地址,位于内核空间。
内核时间管理 1.调用内核时钟接口打印当前时间
(1)创建current_time.c和Makefile文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <linux/module.h> #include <linux/time.h> #include <linux/rtc.h> MODULE_LICENSE("GPL" ); struct timeval tv ;struct rtc_time tm ;static int __init currenttime_init (void ) { int year, mon, day, hour, min, sec; printk("Start current_time module...\n" ); do_gettimeofday(&tv); rtc_time_to_tm(tv.tv_sec, &tm); year = tm.tm_year + 1900 ; mon = tm.tm_mon + 1 ; day = tm.tm_mday; hour = tm.tm_hour + 8 ; min = tm.tm_min; sec = tm.tm_sec; printk("Current time: %d-%02d-%02d %02d:%02d:%02d\n" , year, mon, day, hour, min, sec); return 0 ; } static void __exit currenttime_exit (void ) { printk("Exit current_time module...\n" ); } module_init(currenttime_init); module_exit(currenttime_exit);
1 2 3 4 5 6 7 8 9 10 11 ifneq ($(KERNELRELEASE) ,) obj-m := current_time.o else KERNELDIR ?=/usr/src/kernels/kernel-4.19.90-2405.5.0 PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif .PHONY :cleanclean: -rm *.mod.c *.o *.order *.symvers *.ko
(2)编译运行
1 2 3 4 5 make insmod current_time.ko dmesg | tail -n 2 rmmod current_time dmesg | tail -n 3
(3)结果分析 :成功在在屏幕上打印出格式化的时间、日期,并正确地加载和卸载。
2.编写timer,在特定时刻打印hello,world
(1)创建timer_example.c和Makefile文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <linux/module.h> #include <linux/timer.h> MODULE_LICENSE("GPL" ); struct timer_list timer ;void print (struct timer_list *timer) { printk("hello,world!\n" ); } static int __init timer_init (void ) { printk("Start timer_example module...\n" ); timer.expires = jiffies + 10 * HZ; timer.function = print; add_timer(&timer); return 0 ; } static void __exit timer_exit (void ) { printk("Exit timer_example module...\n" ); } module_init(timer_init); module_exit(timer_exit);
1 2 3 4 5 6 7 8 9 10 11 ifneq ($(KERNELRELEASE) ,)obj-m := timer_example.o else KERNELDIR ?=/usr/src/kernels/kernel-4.19.90-2405.5.0 PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif .PHONY :cleanclean: -rm *.mod.c *.o *.order *.symvers *.ko
(2)编译运行
1 2 3 4 5 6 7 make insmod timer_example.ko dmesg | tail -n 2 dmesg -t | tail -n 2 dmesg -T | tail -n 2 rmmod timer_example dmesg -T | tail -n 3
(3)结果分析
加载该内核模块10秒后打印“hello,world!”,因为定时器执行了定时操作。合理使用定时器,可以使工作在指定时间点上执行,我们只需要执行一些初始化工作,设置一个超时时间,指定超时发生后执行的函数,然后激活定时器就可以了。指定的函数在定时器到期时自动执行。
3.调用内核时钟接口,监控累加计算代码的运行时间
(1)创建sum_time.c和Makefile文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 #include <linux/module.h> #include <linux/time.h> MODULE_LICENSE("GPL" ); #define NUM 100000 struct timeval tv ;static long sum (int num) { int i; long total = 0 ; for (i = 1 ; i <= NUM; i++) total = total + i; printk("The sum of 1 to %d is: %ld\n" , NUM, total); return total; } static int __init sum_init (void ) { int start; int start_u; int end; int end_u; long time_cost; long s; printk("Start sum_time module...\n" ); do_gettimeofday(&tv); start = (int )tv.tv_sec; start_u = (int )tv.tv_usec; printk("The start time is: %d s %d us \n" , start, start_u); s = sum(NUM); do_gettimeofday(&tv); end = (int )tv.tv_sec; end_u = (int )tv.tv_usec; printk("The end time is: %d s %d us \n" , end, end_u); time_cost = (end - start) * 1000000 + end_u - start_u; printk("The cost time of sum from 1 to %d is: %ld us \n" , NUM, time_cost); return 0 ; } static void __exit sum_exit (void ) { printk("Exit sum_time module...\n" ); } module_init(sum_init); module_exit(sum_exit);
1 2 3 4 5 6 7 8 9 10 11 ifneq ($(KERNELRELEASE) ,) obj-m := sum_time.o else KERNELDIR ?=/usr/src/kernels/kernel-4.19.90-2405.5.0 PWD := $(shell pwd) default: $(MAKE) -C $(KERNELDIR) M=$(PWD) modules endif .PHONY :cleanclean: -rm *.mod.c *.o *.order *.symvers *.ko
(2)编译运行
1 2 3 4 5 make insmod sum_time.ko dmesg | tail -n 5 rmmod sum_time dmesg | tail -n 6
(3)结果分析:由程序运行结果可以看出,从1到100000的累加和所花时间是 3 us。
问题及解决方案 问题一: 进行2.1操作系统安装时,进行可视化桌面配置清华源时,没有添加sudo或者切换到root用户,导致一直出现“E212: Can’t open file for writing”。
解决方案: 通过切换root用户或使用sudo命令成功解决,认识到系统文件修改需要管理员权限。
问题二: 进行2.2内核更新中,无法像主机一样复制剪切粘贴移动内核源码文件。
解决方案: 安装VMware Tools或使用命令行进行移动
问题三: 进行2.3内核模块编程部分,总是频繁出现报错。
(1)比如hello.c文件出现编译出错问题
(2)输入make后会出现Mkefile 1:*** 遗漏分隔符(nu)。停止这种错误。
解决方案: 最后发现是hello,c代码出现了一些小的错误。Makefile文件中缺少制表符(Tab)或使用了错误的缩进方式,因为Makefile要求命令必须以Tab开头,不能用空格。
解决问题过程中的参考:
1.解决桌面可视化问题:https://zhuanlan.zhihu.com/p/229861153
2.OpenEuler实验_本次实验服务器已完成内核编译(openeuler 4.19.08),可直接开始实验-CSDN博客
本实验代码参考: LM/OpenEuler_实验
实验总结 通过这次实验,我收获了很多实用的知识和经验。在动手安装openEuler系统的过程中,我学会了如何正确配置和使用这个操作系统。从下载镜像到完成安装,再到创建个性化的用户账号,每一个步骤都让我对系统有了更直观的认识。
在实验中,我不仅成功编译了最新版本的内核,还通过实际操作深入了解了系统是如何进行编程,以及管理内存和时间的。这些经历让我对计算机系统的工作原理有了更清晰的理解,也让我掌握了更多实用的技术。这些知识和技能,不仅对现在的学习很有帮助,也为我以后的工作打下了很好的基础。