美文网首页
[OS64][028]源码阅读:程序5-1 从内核层(0特权级)

[OS64][028]源码阅读:程序5-1 从内核层(0特权级)

作者: AkuRinbu | 来源:发表于2019-06-20 22:16 被阅读0次

    学习笔记

    使用教材(配书源码以及使用方法)
    《一个64位操作系统的设计与实现》
    http://www.ituring.com.cn/book/2450
    https://www.jianshu.com/p/28f9713a9171

    源码结构

    • 配书代码包 :第5章 \ 程序 \ 程序5-1

    程序5-1 运行

    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-1 运行结果.png

    程序 5-1 源码执行流程

    1、到函数 init 为止的流程,可以参考:

    [OS64][026]源码阅读:程序4-11 切换到第二个进程 ,程序执行过程示意图
    https://www.jianshu.com/p/9bcc6d573978

    2、进入程序5-1的 函数 init(task.c):

    unsigned long init(unsigned long arg)
    {
        struct pt_regs *regs;
    
        color_printk(RED,BLACK,"init task is running,arg:%#018lx\n",arg);
    
        current->thread->rip = (unsigned long)ret_system_call;
        current->thread->rsp = (unsigned long)current + STACK_SIZE - sizeof(struct pt_regs);
        regs = (struct pt_regs *)current->thread->rsp;
    
        __asm__ __volatile__    (   "movq   %1, %%rsp   \n\t"
                        "pushq  %2      \n\t"
                        "jmp    do_execve   \n\t"
                        ::"D"(regs),"m"(current->thread->rsp),"m"(current->thread->rip):"memory");
    
        return 1;
    }
    
    • pushq %2 就是push current->thread->rip,就是将ret_system_call入口地址压栈,在函数do_execve返回时,是返回到ret_system_call

    • "D"(regs)就是RDI=regs,之后接函数的jmp do_execve的第一个参数

    3、跳转到函数 do_execve(task.c) :

    // task.c
    void user_level_function()
    {
        color_printk(RED,BLACK,"user_level_function task is running\n");
        while(1);
    }
    
    unsigned long do_execve(struct pt_regs * regs)
    {
        regs->rdx = 0x800000;   //RIP
        regs->rcx = 0xa00000;   //RSP
        regs->rax = 1;  
        regs->ds = 0;
        regs->es = 0;
        color_printk(RED,BLACK,"do_execve task is running\n");
    
        memcpy(user_level_function,(void *)0x800000,1024);
    
        return 0;
    }
    
    // lib.h
    /*      
      From => To memory copy Num bytes
    */
    inline void * memcpy(void *From,void * To,long Num)
    {
    . . .   
    return To;
    }
    
    • memcpy(user_level_function,(void *)0x800000,1024); 把函数user_level_function的全部机器码复制到线性地址0x800000起始处

    • 这里要注意区分,首先,没错,上面的代码函数user_level_function的确是位于源码文件task.c中,的确是位于内核层,但是,执行了语句memcpy之后,这些机器码就被复制到线性地址0x800000处了,我们是说那些位于线性地址0x800000的机器码是用户层

    • 这里在regsRDX字段以及RCX字段填上的数值,0x800000就是用户层代码段的起始地址,0xa00000就是用户层的栈基地址,这是作者顺便选的空闲物理页,只要保证两个值在同一个空闲物理页即可

    • 这里填的是regsRDX字段以及RCX字段,是为了满足后面汇编指令sysexit的参数要求,RDX = 目标代码段的第一条指令地址、RCX=目标代码段的栈基地址,我们现在的目标是3特权级的用户层

    3、从do_execve(task.c) 返回,实则进入函数 ret_system_call(entry.S):

    ENTRY(ret_system_call)                      
        movq    %rax,   0x80(%rsp)       
        popq    %r15                 
        popq    %r14                    
        popq    %r13                    
        popq    %r12                    
        popq    %r11                    
        popq    %r10                    
        popq    %r9                 
        popq    %r8                 
        popq    %rbx                    
        popq    %rcx                    
        popq    %rdx                    
        popq    %rsi                    
        popq    %rdi                    
        popq    %rbp                    
        popq    %rax                    
        movq    %rax,   %ds          
        popq    %rax                 
        movq    %rax,   %es          
        popq    %rax                 
        addq    $0x38,  %rsp    
        .byte   0x48         
        sysexit 
    
    // ptrace.h
    struct pt_regs
    {
        unsigned long r15;
        . . .
        unsigned long rax;
        unsigned long func;
        unsigned long errcode;
        unsigned long rip;
        unsigned long cs;
        unsigned long rflags;
        unsigned long rsp;
        unsigned long ss;
    };      
    
    • 函数do_execvereturn 0;,那么这里一开始的RAX=0
    • 这里依次将结构体pt_regs的数值弹出到CPU的寄存器里面,成就了下面的汇编指令的执行条件
    RDX = 0x800000
    RCX = 0xa00000
    .byte   0x48         
    sysexit 
    
    • 指令sysexit 能且只能从0特权级向3特权级进行跳转
    执行完之后,相当于 RIP =0x800000,跳转到用户层开始执行
    并且设置了RSP=0xa00000 将用户层的栈基地址设置在0xa00000
    

    4、用户层线性地址0x80000:

    |-----  -----|---- kernel -----|---- ----|. . . . . . . . .|--- user ----|
    0           1MB               2MB                          8MB
    
    • 输出黑底红字的字符串"user_level_function task is running\n"

    程序5-1 调试过程

    • 1、运行到00104052: sysexit为止,现在退出,还是处在0特权级(CS段选择子的RPL字段是0)
    Please choose one: [6] 6
    <bochs:1> b 0x10ae30
    <bochs:2> c
    (0) Breakpoint 1, 0xffff80000010ae30 in ?? ()
    Next at t=63148016
    (0) [0x00000010ae30] 0008:ffff80000010ae30 (unk. ctxt): push rbp                  ; 55
    
    <bochs:3> b 0x10af0a
    <bochs:4> c
    00063152000i[XGUI  ] GFX snapshot: 1440 x 900 x 32 bpp (5184000 bytes)
    (0) Breakpoint 2, 0xffff80000010af0a in ?? ()
    Next at t=63245704
    (0) [0x00000010af0a] 0008:ffff80000010af0a (unk. ctxt): mov rsp, qword ptr ds:[rbx+16] ; 488b6310
    
    <bochs:5> s
    Next at t=63245705
    (0) [0x00000010af0e] 0008:ffff80000010af0e (unk. ctxt): push qword ptr ds:[rdx+8] ; ff7208
    
    <bochs:6> s
    Next at t=63245706
    (0) [0x00000010af11] 0008:ffff80000010af11 (unk. ctxt): jmp .-381 (0xffff80000010ad99) ; e983feffff
    
    <bochs:7> print-stack
    Stack address size 8
     | STACK 0xffff800000207f38 [0xffff8000:0x00104027]
     
    <bochs:8> s
    Next at t=63245707
    (0) [0x00000010ad99] 0008:ffff80000010ad99 (unk. ctxt): push rbp                  ; 55
    
    <bochs:9> b 0x10ae2f
    <bochs:10> c
    (0) Breakpoint 3, 0xffff80000010ae2f in ?? ()
    Next at t=63302538
    (0) [0x00000010ae2f] 0008:ffff80000010ae2f (unk. ctxt): ret                       ; c3
    
    <bochs:11> s
    Next at t=63302539
    (0) [0x000000104027] 0008:ffff800000104027 (unk. ctxt): mov qword ptr ss:[rsp+128], rax ; 4889842480000000
    
    
    <bochs:16> u 0x104027 0x104055
    00104027: (                    ): mov qword ptr ss:[rsp+128], rax ; 4889842480000000
    0010402f: (                    ): pop r15                   ; 415f
    00104031: (                    ): pop r14                   ; 415e
    00104033: (                    ): pop r13                   ; 415d
    00104035: (                    ): pop r12                   ; 415c
    00104037: (                    ): pop r11                   ; 415b
    00104039: (                    ): pop r10                   ; 415a
    0010403b: (                    ): pop r9                    ; 4159
    0010403d: (                    ): pop r8                    ; 4158
    0010403f: (                    ): pop rbx                   ; 5b
    00104040: (                    ): pop rcx                   ; 59
    00104041: (                    ): pop rdx                   ; 5a
    00104042: (                    ): pop rsi                   ; 5e
    00104043: (                    ): pop rdi                   ; 5f
    00104044: (                    ): pop rbp                   ; 5d
    00104045: (                    ): pop rax                   ; 58
    00104046: (                    ): mov ds, ax                ; 488ed8
    00104049: (                    ): pop rax                   ; 58
    0010404a: (                    ): mov es, ax                ; 488ec0
    0010404d: (                    ): pop rax                   ; 58
    0010404e: (                    ): add rsp, 0x0000000000000038 ; 4883c438
    00104052: (                    ): sysexit                   ; 480f35
    
    <bochs:21> q
    00063302539i[      ] dbg: Quit
    00063302539i[CPU0  ] CPU is in long mode (active)
    00063302539i[CPU0  ] CS.mode = 64 bit
    00063302539i[CPU0  ] SS.mode = 64 bit
    00063302539i[CPU0  ] | RCX=0000000000000000  RDX=0000000000000400
    00063302539i[CPU0  ] | RSP=ffff800000207f40  
    00063302539i[CPU0  ] | SEG sltr(index|ti|rpl)     base    limit G D
    00063302539i[CPU0  ] |  CS:0008( 0001| 0|  0) 00000000 00000000 0 0
    00063302539i[CPU0  ] |  DS:0010( 0002| 0|  0) 00000000 00000000 0 0
    00063302539i[CPU0  ] |  SS:0010( 0002| 0|  0) 00000000 00000000 0 0
    00063302539i[CPU0  ] | RIP=ffff800000104027 (ffff800000104027)
    00063302539i[CMOS  ] Last time is 1561038347 (Thu Jun 20 21:45:47 2019)
    00063302539i[XGUI  ] Exit
    00063302539i[SIM   ] quit_sim called with exit code 0
    
    
    • 2、重新运行一次,这一次执行了sysexit指令,就去到了线性地址0x800000处开始的用户层,CS段选择子的RPL变成3了
    Please choose one: [6] 6
    (0) [0x0000fffffff0] f000:fff0 (unk. ctxt): jmpf 0xf000:e05b          ; ea5be000f0
    <bochs:1> b 0x104052
    <bochs:2> c
    (0) Breakpoint 1, 0xffff800000104052 in ?? ()
    Next at t=63285312
    (0) [0x000000104052] 0008:ffff800000104052 (unk. ctxt): sysexit                   ; 480f35
    
    <bochs:10> q
    00063285313i[      ] dbg: Quit
    00063285313i[CPU0  ] CPU is in long mode (active)
    00063285313i[CPU0  ] CS.mode = 64 bit
    00063285313i[CPU0  ] SS.mode = 64 bit 
    00063285313i[CPU0  ] | RCX=0000000000a00000  RDX=0000000000800000
    00063285313i[CPU0  ] | RSP=0000000000a00000 
    00063285313i[CPU0  ] | SEG sltr(index|ti|rpl)     base    limit G D
    00063285313i[CPU0  ] |  CS:002b( 0005| 0|  3) 00000000 ffffffff 1 0
    00063285313i[CPU0  ] |  DS:0000( 0000| 0|  0) 00000000 00000000 0 0
    00063285313i[CPU0  ] |  SS:0033( 0006| 0|  3) 00000000 ffffffff 1 1
    00063285313i[CPU0  ] | RIP=0000000000800000 (0000000000800000)
    00063285313i[CMOS  ] Last time is 1561039536 (Thu Jun 20 22:05:36 2019)
    00063285313i[XGUI  ] Exit
    00063285313i[SIM   ] quit_sim called with exit code 0
    
    

    相关文章

      网友评论

          本文标题:[OS64][028]源码阅读:程序5-1 从内核层(0特权级)

          本文链接:https://www.haomeiwen.com/subject/zyrsqctx.html