實(shí)驗(yàn)要求?
- 掌握Linux 內(nèi)核的編譯與安裝
- 掌握Linux 系統(tǒng)調(diào)用基本概念
- 設(shè)計(jì)和添加linux系統(tǒng)調(diào)用
????????(1)修改或返回指定進(jìn)程的優(yōu)先級(nice值和prio值)(詳見教材P328)提示:可能參考的內(nèi)核函數(shù):set_user_nice().
????????(2)改變主機(jī)名稱為自定義字符串(自選題目)
?1、Linux 內(nèi)核的編譯與安裝? ?(使用華為云,完成openEuler內(nèi)核的編譯與安裝)
(1)登錄系統(tǒng)并查看當(dāng)前內(nèi)核版本
[root@openEuler ~]# uname -r
?(2)安裝工具,構(gòu)建開發(fā)環(huán)境
[root@openEuler ~]# yum group install -y "Development Tools"
[root@openEuler ~]# yum install -y bc
[root@openEuler ~]# yum install -y openssl-devel
(3)備份boot目錄以防后續(xù)步驟更新內(nèi)核失敗
[root@openEuler ~]# tar czvf boot.origin.tgz /boot/
保存當(dāng)前內(nèi)核版本信息
[root@openEuler ~]# uname –r > uname_r.log
(4)獲取內(nèi)核源代碼并解壓
[root@openEuler ~]# wget https://gitee.com/openeuler/kernel/repository/archive/kernel-4.19.zip
[root@openEuler ~]# unzip kernel-4.19.zip
(5)編譯內(nèi)核
?[root@openEuler ~]# cd kernel-kernel-4.19
[root@openEuler kernel]# make openeuler_defconfig
[root@openEuler kernel]# make -j4 Image modules dtbs
這一步是編譯內(nèi)核的Image、modules和dtbs,make -j 4表示4個(gè)線程編譯(可以根據(jù)CPU核數(shù)調(diào)整)
?(6)安裝內(nèi)核
[root@openEuler kernel]# make modules_install
[root@openEuler kernel]# make install
注意:在最后一步“make install”時(shí)出現(xiàn)的錯(cuò)誤在這里可以忽略。
(7)以VNC登錄ECS
(8)重啟系統(tǒng)
[root@openEuler kernel]# reboot
?(9)登錄并驗(yàn)證
在VNC窗口中選擇以新編譯出來的內(nèi)核啟動系統(tǒng)
?這里編譯完以后已經(jīng)有了4.19.208版本的新內(nèi)核,選擇該內(nèi)核登錄
?
2、掌握Linux 系統(tǒng)調(diào)用基本概念?
Linux系統(tǒng)處理系統(tǒng)調(diào)用的流程以及增加系統(tǒng)調(diào)用的方法。Linux系統(tǒng)提供了多達(dá)幾百種的系統(tǒng)調(diào)用,為了唯一地標(biāo)識每一個(gè)系統(tǒng)調(diào)用,Linux為每個(gè)系統(tǒng)調(diào)用都設(shè)置了一個(gè)唯一的編號,稱為系統(tǒng)調(diào)用號,同時(shí)每個(gè)系統(tǒng)調(diào)用需要一個(gè)服務(wù)例程完成其具體功能。
這里不做過多描述。
(重點(diǎn)是怎么添加系統(tǒng)調(diào)用!?。。?/p>
- 閱讀教材7.2.3節(jié)Linux 添加系統(tǒng)調(diào)用的步驟,添加一個(gè)新的系統(tǒng)調(diào)用,通過內(nèi)核打印調(diào)試語句printk打印自己的學(xué)號。
- cd kernel-kernel-4.19 進(jìn)入文件夾
- vim?include/uapi/asm-generic/unistd.h 修改及添加系統(tǒng)調(diào)用號(注意系統(tǒng)調(diào)用號不能隨意加,只能一次加1)
#define __NR_hello_euler 294
__SYSCALL(__NR_hello_euler, sys_hello_euler)
#undef __NR_syscalls
#define __NR_syscalls 295
- ?vim include/linux/syscalls.h 添加代碼申明系統(tǒng)調(diào)用服務(wù)例程
asmlinkage long sys_hello_euler(void);
- ?vim?kernel/sys.c?實(shí)現(xiàn)系統(tǒng)調(diào)用服務(wù)例程
SYSCALL_DEFINE0(hello_euler)
{
printk(KERN_INFO "xuehao:20273108");
return 0;
}
- 重新編譯,安裝內(nèi)核
- 配置內(nèi)核:make openeuler_defconfig
編譯內(nèi)核:make -j4 Image modules dtbs
安裝模塊:make modules_install
安裝內(nèi)核:make install
立即重啟:reboot? ?(重啟后進(jìn)入新內(nèi)核)
重啟后
- cd kernel-kernel-4.19 進(jìn)入文件夾
vim testhello.c??編寫測試代碼testhello.c
#include <stdio.h>
#include <unistd.h>
#include <sys/syscall.h>
int main()
{
ret = syscall(294);
return 0;
}
- ?編譯 gcc testhello.c
- 輸入 ls ,會發(fā)現(xiàn)出現(xiàn)了a.out 文件(在使用gcc編程時(shí),沒有指定輸入可執(zhí)行文件名,默認(rèn)生成可執(zhí)行文件a.out文件。)
- ? 執(zhí)行?./a.out
- 輸入 dmesg 查看結(jié)果(成功輸出學(xué)號~)
?
3、設(shè)計(jì)和添加linux系統(tǒng)調(diào)用?
(1)修改或返回指定進(jìn)程的優(yōu)先級(nice值和prio值)(詳見教材P328)提示:可能參考的內(nèi)核函數(shù):set_user_nice().
- vim?include/uapi/asm-generic/unistd.h 修改及添加系統(tǒng)調(diào)用號
#define __NR_mysetnice 295 __SYSCALL(__NR_mysetnice,sys_mysetnice)
注意下面的? #define __NR_syscalls 295 要變成? #define __NR_syscalls 296
- ??vim include/linux/syscalls.h 添加代碼申明系統(tǒng)調(diào)用服務(wù)例程
asmlinkage long sys_mysetnice(pid_t pid,int flag,int nicevalue,void __user*prio,void __user*nice);
- ??vim?kernel/sys.c?實(shí)現(xiàn)系統(tǒng)調(diào)用服務(wù)例程
SYSCALL_DEFINE5(mysetnice,pid_t,pid,int,flag,int,nicevalue,void __user*,prio,void __user*,nice) { int n; int p; struct pid * kpid; struct task_struct * task; kpid = find_get_pid(pid);/*得到pid */ task = pid_task(kpid, PIDTYPE_PID);/* 返回task_struct */ n = task_nice(task);/* 返回進(jìn)程當(dāng)前nice值 */ p = task_prio(task);/*返回進(jìn)程當(dāng)前prio值*/ if(flag == 1) { set_user_nice(task, nicevalue);/* 修改進(jìn)程nice值 */ n = task_nice(task);/*重新取得進(jìn)程nice值*/ p = task_prio(task);/*重新取得進(jìn)程prio值*/ copy_to_user(nice,&n,sizeof(n));/*將nice值拷貝到用戶空間*/ copy_to_user(prio,&p,sizeof(p));/*將prio值拷貝到用戶空間*/ return 0; } else if(flag == 0) { copy_to_user(nice,&n,sizeof(n));/*將nice值拷貝到用戶空間*/ copy_to_user(prio,&p,sizeof(p));/*將prio值拷貝到用戶空間*/ return 0; } return EFAULT; }
- 同上,重新編譯安裝內(nèi)核?
- 配置內(nèi)核:make openeuler_defconfig
編譯內(nèi)核:make -j4 Image modules dtbs
安裝模塊:make modules_install
安裝內(nèi)核:make install
立即重啟:reboot? ?(重啟后進(jìn)入新內(nèi)核)
- cd kernel-kernel-4.19 進(jìn)入文件夾
vim my_setnice.c??編寫測試代碼my_setnice.c
#define _GNU_SOURCE #include<unistd.h> #include<sys/syscall.h> #include<stdio.h> #include<stdlib.h> int main() { pid_t pid; int nicevalue; int flag; int n=0; int p=0; int *prio; int *nice; prio = &p; nice = &n; printf("請輸入pid: \n"); scanf("%d",&pid); printf("pid輸入成功\n請輸入nice值:\n"); scanf("%d",&nicevalue); printf("nice輸入成功\n請輸入flag(flag為1時(shí)修改,為0時(shí)查看):\n"); scanf("%d",&flag); syscall(295,pid,flag,nicevalue,prio,nice); printf("現(xiàn)在的nice為%d,prio為%d\n",n,p); return 0; }
- gcc my_setnice.c
- ./a.out?
?
?(2)改變主機(jī)名稱為自定義字符串(自選題目)
- ?vim?include/uapi/asm-generic/unistd.h 修改及添加系統(tǒng)調(diào)用號
#define __NR_mysethostname 296 __SYSCALL(__NR_mysethostname,sys_mysethostname)
同理,下面的? #define __NR_syscalls 296 要變成? #define __NR_syscalls 297
- ?vim include/linux/syscalls.h 添加代碼申明系統(tǒng)調(diào)用服務(wù)例程
asmlinkage long sys_mysethostname(char __user *name, int len);
- ?vim?kernel/sys.c?實(shí)現(xiàn)系統(tǒng)調(diào)用服務(wù)例程
SYSCALL_DEFINE2(mysethostname, char __user *, name, int, len) { int errno; char tmp[__NEW_UTS_LEN]; /*__NEW_UTS_LEN=64*/ if(len<0 || len>__NEW_UTS_LEN) return -EINVAL; errno = -EFAULT; if(!copy_from_user(tmp, name, len)) /*copy_from_user將name指向的字符串從用戶空間拷貝到內(nèi)核空間,失敗返回沒有被拷貝的字節(jié)數(shù),成功返回0*/ { struct new_utsname *u; down_write(&uts_sem); /*寫者使用該函數(shù)來得到讀寫信號量sem,它會導(dǎo)致調(diào)用者睡眠,只能在進(jìn)程上下文使用,用于獲取Linux內(nèi)核讀寫信號量中的寫鎖*/ u = utsname(); /*獲取當(dāng)前內(nèi)核名稱和其它信息,成功執(zhí)行時(shí),返回0。失敗返回-1,errno被設(shè)為EFAULT,表示buf無效*/ memcpy(u->nodename, tmp, len); /*從源內(nèi)存地址的起始位置開始拷貝若干個(gè)字節(jié)到目標(biāo)內(nèi)存地址中*/ memset(u->nodename + len, 0, sizeof(u->nodename)- len); errno = 0; uts_proc_notify(UTS_PROC_HOSTNAME); /*使用UTS namespace隔離hostname*/ up_write(&uts_sem); /*釋放寫鎖*/ } return errno; }
- 同上重新編譯內(nèi)核?
- cd kernel-kernel-4.19 進(jìn)入文件夾
vim sethostname.c??編寫測試代碼sethostname.c
#define _GUN_SOURCE #include<unistd.h> #include<sys/syscall.h> #include<stdio.h> int main() { syscall(296,"xjyxjy",6); return 0; }
- gcc sethostname.c
- ./sethostname
- 輸入命令hostname或者重新在終端上連接ssh,即可看到主機(jī)名已經(jīng)成功更換
?
?4、實(shí)驗(yàn)總結(jié)
(1)大家做實(shí)驗(yàn)之前看教程一定要搞清楚是x86還是arm架構(gòu)的呀?。?!我就是在這上面栽跟頭了重建了三四次華為云
(2)如果用VNC登陸時(shí)出現(xiàn)以下報(bào)錯(cuò),那么恭喜你,多半是你的內(nèi)核崩了~我的老師說,只要你手速夠快,在重啟虛擬機(jī)的時(shí)候立馬用VNC重新登陸是可以進(jìn)去的,但是我沒成功過,只能重建了n次云主機(jī)。
?
(3)雖然老師給的實(shí)驗(yàn)報(bào)告里要求VNC登錄,但我個(gè)人建議使用cloudshell來執(zhí)行命令。
(4)在驗(yàn)收的時(shí)候,被老師冷不丁問了系統(tǒng)調(diào)用里的函數(shù)的意義和用法,直接栽跟頭了。我會在下面po出一部分內(nèi)部函數(shù)的意義及用法。
1.find_get_pid(pid)
find_get_pid 在內(nèi)核中有不同的命名空間,在各自的命名空間同一個(gè)進(jìn)程pid值可能是不一樣的,find_get_pid為了找到在內(nèi)核態(tài)中的我們尋找進(jìn)程真正的pid
2.set_user_nice(task, nicevalue)
用于設(shè)置進(jìn)程的nice值
3.copy_to_user()
完成內(nèi)核空間到用戶空間的復(fù)制,To 目標(biāo)地址,這個(gè)地址是用戶空間的地址;From 源地址,這個(gè)地址是內(nèi)核空間的地址; N 將要拷貝的數(shù)據(jù)的字節(jié)數(shù)。
如果數(shù)據(jù)拷貝成功,則返回零;否則,返回沒有拷貝成功的數(shù)據(jù)字節(jié)數(shù)。4.copy_from_user()
copy_from_user將name指向的字符串從用戶空間拷貝到內(nèi)核空間,失敗返回沒有被拷貝的字節(jié)數(shù),成功返回0。
5.down_write()
函數(shù)down_write()是寫者用來得到讀寫信號量sem時(shí)調(diào)用的,如果該信號量被讀者或?qū)懻咚钟校瑒t對該函數(shù)的調(diào)用會導(dǎo)致調(diào)用者的睡眠,只能在進(jìn)程上下文使用,用于獲取Linux內(nèi)核讀寫信號量中的寫鎖。文章來源:http://www.zghlxwxcb.cn/news/detail-419615.html
6.memcpy(str1, str2,? n)?
從存儲區(qū)?str2?復(fù)制?n?個(gè)字節(jié)到存儲區(qū)?str1。文章來源地址http://www.zghlxwxcb.cn/news/detail-419615.html
到了這里,關(guān)于杭電操作系統(tǒng)實(shí)驗(yàn)一 --- Linux內(nèi)核編譯及添加系統(tǒng)調(diào)用(arm架構(gòu)華為云)的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!