[OS64][029]源碼閱讀:程序5-2 從用戶層(3特權級)到 內(nèi)核層(0特權級)再回 用戶層(3特權級)

學習筆記

使用教材(配書源碼以及使用方法)
《一個64位操作系統(tǒng)的設計與實現(xiàn)》
http://www.ituring.com.cn/book/2450
http://www.reibang.com/p/28f9713a9171

源碼結構

  • 配書代碼包 :第5章 \ 程序 \ 程序5-2

程序5-2 運行

ls
cd bootloader
make clean
make
cd ../

cd kernel
make clean
make

cd ../
sudo mount boot.img media -t vfat -o loop
sudo cp bootloader/loader.bin media
sync
sudo cp bootloader/boot.bin media
sync
sudo cp kernel/kernel.bin media
sync

bochs -f ./bochsrc
程序5-2運行結果

程序5-2 執(zhí)行過程

一、到 user_level_function()為止的流程參考

[OS64][028]源碼閱讀:程序5-1 從內(nèi)核層(0特權級)到用戶層(3特權級)
http://www.reibang.com/p/37f2f96db932

  • 為了執(zhí)行sysenter指令而在 init_task()函數(shù)中新增的代碼
init_task() {
. . .
    wrmsr(0x174,KERNEL_CS);   // 程序5-1已有
    wrmsr(0x175,current->thread->rsp0);  // new
    wrmsr(0x176,(unsigned long)system_call); // new
. . .
}
    
init_task() 毫無疑問運行在 內(nèi)核層,
current是一個宏况增,目的是獲取當前的進程結構體劣纲,
那么挎塌,很明顯采缚,此處的current獲取到的就是 屬于內(nèi)核層的進程結構體
自然嘴脾,current->thread->rsp0 就是內(nèi)核層的検永郑基地址
內(nèi)核層的椔宀螅空間本質(zhì)上就是全局變量聯(lián)合體union task_union init_task_union其中的數(shù)組空間

參考 [OS64][025]源碼閱讀:程序4-11:運行結果,數(shù)據(jù)結構佑淀,第一個進程init_task_union
[http://www.reibang.com/p/b30fb97a1dc4](http://www.reibang.com/p/b30fb97a1dc4)

二留美、進入位于用戶層user_level_function()的函數(shù)

void user_level_function()
{
    long ret = 0;
    color_printk(RED,BLACK,"user_level_function task is running\n");

    __asm__ __volatile__    (   "leaq   sysexit_return_address(%%rip),  %%rdx   \n\t"
                    "movq   %%rsp,  %%rcx       \n\t"
                    "sysenter           \n\t"
                    "sysexit_return_address:    \n\t"
                    :"=a"(ret):"0"(15):"memory");   

    color_printk(RED,BLACK,"user_level_function task called sysenter,ret:%ld\n",ret);

    while(1);
}
  • :"=a"(ret):"0"(15): 相當于輸入是 RAX=15 、輸出時有 ret=RAX

  • leaq sysexit_return_address(%%rip), %%rdx 把應用程序的返回地址(即返回到標號處)填入RDX(等下回來就是回來到標號sysexit_return_address:處)

  • movq %%rsp, %%rcx 將當前的CPU 寄存器RSP填入CPU寄存器RCX,當執(zhí)行到函數(shù)user_level_function()時谎砾,已經(jīng)是位于用戶層了逢倍,因此當前的RSP就是指向用戶層的棧基地址景图,毫無疑問這里的值應該就是硬編碼的0xa00000(等下回來時候要用)

  • sysenter 较雕,兩個需要的參數(shù)是上面的wrmsr提供的,接著會跳轉到 system_call

三挚币、實現(xiàn) 3特權級 到 0特權級: sysenter

  • 1亮蒋、system_call 最后是一句callq system_call_function
 sysenter  會導致 EFLAGS 的 if 標志位復位 即不允許中斷
這里手動打開,允許中斷 妆毕,使用指令 sti

ENTRY(system_call)
    sti
    subq    $0x38,  %rsp             
    cld;                     

    pushq   %rax;                   
     . . .          
    pushq   %r15;                   
    movq    $0x10,  %rdx;               
    movq    %rdx,   %ds;                
    movq    %rdx,   %es;             
    movq    %rsp,   %rdi                
            
    callq   system_call_function            ////////

ENTRY(ret_system_call)                      
    movq    %rax,   0x80(%rsp)       
    popq    %r15                 
    . . .        
    popq    %rax                 
    addq    $0x38,  %rsp    
    .byte   0x48         
    sysexit                  


這兩個代碼段慎玖,在源碼文件entry.S就是連在一起的,
下面是反匯編后它們的機器碼以及線性地址:

ffff800000104027 <system_call>:
ffff800000104027:   fb                      sti    
. . .
ffff80000010405c:   48 89 e7                mov    %rsp,%rdi
ffff80000010405f:   e8 da 72 00 00          callq  ffff80000010b33e <system_call_function>


ffff800000104064 <ret_system_call>:
ffff800000104064:   48 89 84 24 80 00 00    mov    %rax,0x80(%rsp)
. . .
ffff80000010407d:   59                      pop    %rcx
ffff80000010407e:   5a                      pop    %rdx
. . .
ffff80000010408f:   48 0f 35                rex.W sysexit 

  • 2笛粘、system_call_function帶著從no_system_call來的返回值RAX=-1是返回到哪里呢趁怔?
unsigned long  system_call_function(struct pt_regs * regs)
{
    return system_call_table[regs->rax](regs);
}
#define MAX_SYSTEM_CALL_NR 128

函數(shù)指針類型
返回值是 unsigned long
傳入?yún)?shù)是 結構體pt_regs指針 
typedef unsigned long (* system_call_t)(struct pt_regs * regs);

unsigned long no_system_call(struct pt_regs * regs)
{
    color_printk(RED,BLACK,"no_system_call is calling,NR:%#04x\n",regs->rax);
    return -1;
}

目前全部的 系統(tǒng)調(diào)用處理函數(shù) 都設置成 no_system_call
system_call_t system_call_table[MAX_SYSTEM_CALL_NR] = 
{
    [0 ... MAX_SYSTEM_CALL_NR-1] = no_system_call
};

  • 3、由于 callqretq 是一一對應的薪前,那么其實就是返回到 callq system_call_function 后一條指令處润努,即ret_system_call入口地址

四、實現(xiàn) 0特權級 回到 3特權級 : sysexit

ffff800000104064 <ret_system_call>:
ffff800000104064:   48 89 84 24 80 00 00    mov    %rax,0x80(%rsp)
. . .
ffff80000010407d:   59                      pop    %rcx
ffff80000010407e:   5a                      pop    %rdx
. . .
ffff80000010408a:   58                      pop    %rax
ffff80000010408b:   48 83 c4 38             add    $0x38,%rsp
ffff80000010408f:   48 0f 35                rex.W sysexit 

兩條popq語句示括,填好了
RDX = 用戶層 user_level_function() 的標號sysexit_return_address: 處
RCX = 用戶層的椘探剑基地址

五、回到 用戶層 user_level_function() 的標號 sysexit_return_address: 處

void user_level_function()
{
    long ret = 0;
    color_printk(RED,BLACK,"user_level_function task is running\n");

    __asm__ __volatile__    (   . . .
                    "sysexit_return_address:    \n\t"
                    :"=a"(ret):"0"(15):"memory");   

    color_printk(RED,BLACK,"user_level_function task called sysenter,ret:%ld\n",ret);

    while(1);
}
  • 回來了例诀,還帶著返回值RAX=-1随抠,繼續(xù)執(zhí)行,輸出字符串黑底紅字的user_level_function task called sysenter,ret:-1

程序5-2 調(diào)試過程

  • 驗證:return system_call_table[regs->rax](regs); 是不是返回到了 <ret_system_call>:
<bochs:1> b 0x10b36d
<bochs:2> c
(0) Breakpoint 1, 0xffff80000010b36d in ?? ()
Next at t=63456943
(0) [0x00000010b36d] 0008:ffff80000010b36d (unk. ctxt): ret                       ; c3

<bochs:3> print-stack
Stack address size 8
 | STACK 0xffff80000011ff38 [0xffff8000:0x00104064]

<bochs:4> s
Next at t=63456944
(0) [0x000000104064] 0008:ffff800000104064 (unk. ctxt): mov qword ptr ss:[rsp+128], rax ; 4889842480000000

直接斷點設置到system_call_function的return語句:
ffff80000010b33e <system_call_function>:
. . .
ffff80000010b36d:   c3                      retq  

0x 104064 處就是 ret_system_call的入口地址:
ffff800000104064 <ret_system_call>:
最后編輯于
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末繁涂,一起剝皮案震驚了整個濱河市拱她,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌扔罪,老刑警劉巖秉沼,帶你破解...
    沈念sama閱讀 218,755評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異矿酵,居然都是意外死亡唬复,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,305評論 3 395
  • 文/潘曉璐 我一進店門全肮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來敞咧,“玉大人,你說我怎么就攤上這事辜腺⌒萁ǎ” “怎么了乍恐?”我有些...
    開封第一講書人閱讀 165,138評論 0 355
  • 文/不壞的土叔 我叫張陵,是天一觀的道長测砂。 經(jīng)常有香客問我茵烈,道長,這世上最難降的妖魔是什么砌些? 我笑而不...
    開封第一講書人閱讀 58,791評論 1 295
  • 正文 為了忘掉前任呜投,我火速辦了婚禮,結果婚禮上存璃,老公的妹妹穿的比我還像新娘仑荐。我一直安慰自己,他們只是感情好有巧,可當我...
    茶點故事閱讀 67,794評論 6 392
  • 文/花漫 我一把揭開白布释漆。 她就那樣靜靜地躺著悲没,像睡著了一般篮迎。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上示姿,一...
    開封第一講書人閱讀 51,631評論 1 305
  • 那天甜橱,我揣著相機與錄音,去河邊找鬼栈戳。 笑死岂傲,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的子檀。 我是一名探鬼主播镊掖,決...
    沈念sama閱讀 40,362評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼褂痰!你這毒婦竟也來了亩进?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 39,264評論 0 276
  • 序言:老撾萬榮一對情侶失蹤缩歪,失蹤者是張志新(化名)和其女友劉穎归薛,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體匪蝙,經(jīng)...
    沈念sama閱讀 45,724評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡主籍,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,900評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了逛球。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片千元。...
    茶點故事閱讀 40,040評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖颤绕,靈堂內(nèi)的尸體忽然破棺而出幸海,到底是詐尸還是另有隱情蜡歹,我是刑警寧澤,帶...
    沈念sama閱讀 35,742評論 5 346
  • 正文 年R本政府宣布涕烧,位于F島的核電站月而,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏议纯。R本人自食惡果不足惜父款,卻給世界環(huán)境...
    茶點故事閱讀 41,364評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望瞻凤。 院中可真熱鬧憨攒,春花似錦、人聲如沸阀参。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,944評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽蛛壳。三九已至杏瞻,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間衙荐,已是汗流浹背捞挥。 一陣腳步聲響...
    開封第一講書人閱讀 33,060評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留忧吟,地道東北人砌函。 一個月前我還...
    沈念sama閱讀 48,247評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像溜族,于是被迫代替她去往敵國和親讹俊。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,979評論 2 355