linux shell 宏定义_linux内核修炼之系统调用
fork()這個系統調用是有兩個返回值的,在子進程中的返回值是0,在父進程中的返回值是PID,如下
圖 fork一次 返回兩次關于0x80中斷和特權級檢查
在mian函數的sched_init()函數中調用宏:set_system_gate(0x80,&system_call);將0x80號中斷安裝到中斷表里。可見將0x80中斷安裝進了head.s中定義的IDT表中的第0x80項,將中斷函數入口偏移地址設置為system_call,將特權級設置為3。至于為什么沒有看見可以自定義段描述符的地方,因為set_system_gate這個宏的作用是用來安裝系統調用中斷,而系統調用函數是內核函數,內核所在的代碼段描述符值是0x8,這個是已經定死了的。安裝描述符時不需要修改。
IDT表項安裝好后,一旦用戶程序執行0x80中斷,則首先進行特權檢查,用戶程序的CPL為3,0x80中斷的DPL也為3,因此可以執行該中斷,中斷將跳入內核函數中執行,硬件會自動得將0x8寫入CS,將偏移地址寫入EIP,從而執行systemcall,且CPL此時也已被修改為0,從而完成了特權級切換。
當使用jumpi指令進行段間跳轉的時候會對比CS中的CPL和目標GDT中的代碼段的DPL,段內跳轉不對比;當使用mov的指令進行段間內存訪問會對比DS中的CPL和目標GDT中的代碼段的DPL,段內內存訪問不對比,使用中斷跳到中斷服務程序的時候也會發生段間跳轉,此時會對比CS中的CPL和IDT表項中的DPL。
圖 安裝中斷的宏使用bochs進行實驗時,需要關注兩個文件,一個是源碼文件夾linux-0.11下的image文件,一個是oslab文件夾下的hdc-0.11-new.img 文件,源碼文件夾下的image文件每次編譯源碼時都會重新生成,是內核代碼文件;而.img是一個根文件系統鏡像,他與/linux-0.11文件夾下的源碼無關。
Bochs會虛擬出一個軟盤和一個硬盤,軟盤中放image,硬盤中放.img,bochs在啟動是會從軟盤啟動,從而將image中的之前講的bootset 、setup、 head和 sys內核程序按照之前講過的順序邊讀入內存邊執行。當執行到main()中的init()函數時,這個函數的第一句話 setup((void *) &drive_info); 就是調用setup系統調用,安裝根目錄文件系統,如果此時沒有.img文件,則可以在虛擬機頁面中看到loading system…之后便報錯,報錯的語句是printk("Unable to read partition table of drive %dnr", 可以在代碼中搜到,即在執行setup系統調用時報錯。
文件系統加載完成后,就可以在shell中用ls查看各種文件和目錄。當然也可以不啟動linux0.11,而是在Ubuntu中將.img文件mount到某個目錄下,則點進去看到的東西跟啟動linux0.11后的根文件目錄ls后看到的一樣。
李志軍老師的系統調用試驗新增三個文件:who.c 、iam.c和whoami.c三個文件。其中who.c是新增的內核文件,寫好放在源碼的kernel文件夾下,至于為什么要用get_fs_byte來實現內存的訪問,因為內核中的ds描述符默認是內核數據段,而我們實際也需要訪問用戶數據段,需要用到fs描述符,因此要加一層封裝,這點在李老師書里詳細說明。
who.c 寫好后需要重新編譯內核然后bochs加載進入shell,在shell中新建iam.c和whoami.c然后進行編譯。編譯出來的是用戶程序,這兩個c文件在編譯的時候需要 編譯一個_syscall2(int, whoami, char*, name, unsigned int, size);這種宏,宏中有一個變量是在unistd.h中定義的,要修改這個文件不應該在linux0.11的源碼中找,而應該需要在文件系統中的/usr/include文件夾中找到并修改,因為源碼此時已經編譯成內核轉載軟驅載入內存中在跑,修改源碼的源文件無意義。在shell的環境中找到include的文件,并進行修改。
#include <string.h> #include <errno.h> #include <asm/segment.h>char msg[24];int sys_iam(const char * name) {char tep[26];int i = 0;for(; i < 26; i++){tep[i] = get_fs_byte(name+i);if(tep[i] == '0') break;}if (i > 23) return -(EINVAL);strcpy(msg, tep);return i; }int sys_whoami(char * name, unsigned int size) {int len = 0;for (;msg[len] != '0'; len++);if (len > size) {return -(EINVAL);}int i = 0;for(i = 0; i < size; i++){put_fs_byte(msg[i], name+i);if(msg[i] == '0') break;}return i; }圖 who.c代碼
總結
以上是生活随笔為你收集整理的linux shell 宏定义_linux内核修炼之系统调用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: UIBOT调试时步入的快捷键_远程调试
- 下一篇: it培训机构多少钱啊?