MIT-6.S081-2020實驗(xv6-riscv64)二:syscall


實驗文檔

概述

實驗二主要涉及對系統函數調用過程的理解以及嘗試自己手動添加系統調用。首先需要大致了解一下xv6系統調用的過程,這里以fork為例:

根據這個過程,就很容易完成本次實驗了。

內容

trace

該實驗需要打印其他系統調用的信息。根據上面的分析和文檔說明,首先需要給user.h、usys.pl(用來生成usys.S的輔助腳本)和syscall.h添加對應的函數的系統調用號,然后給syscall.c的系統調用數組添加對應的函數指針和函數頭,在sysproc.c添加對應的函數實現,sysproc.c里主要是接收參數並給proc結構體復制,具體代碼如下:

uint64 sys_trace(void) {
    int mask;
    if (argint(0, &mask) < 0) return -1;
    myproc()->mask = mask; return 0;
}

這樣trace函數調用就完成了,但實際功能並沒有實現,真正打印其他系統調用信息的操作應該在syscall.c中進行,在syscall函數的末尾(其他系統調用結束后)輸出信息:

  if (p->mask & (1 << num))
       printf("%d: syscall %s -> %d\n", p->pid, callnames[num - 1], p->trapframe->a0);

sysinfo

添加系統調用的過程和上一個人物類似,這里就不提了。具體sys_sysinfo函數的實現需要首先獲得所需要的信息,然后獲得傳進系統調用函數的地址參數,將獲得的信息復制到這個地址,由於是涉及內核態和用戶態的地址轉換,所以需要使用copyout函數:

uint64 sys_sysinfo(void) {
    uint64 ip; struct sysinfo si;
    si.freemem = freemem();
    si.nproc = nproc();
    if (argaddr(0, &ip) < 0) return -1;
    if(copyout(myproc()->pagetable, ip, (char *)&si, sizeof(si)) < 0)
        return -1;
    return 0;
}

關於freemem函數,這里就需要理解kalloc.c的內容了,這個文件主要進行物理內存的管理,使用一個鏈表來管理空閑空間,而且一個鏈表節點就代表一頁,所以遍歷整個鏈表,節點數乘上內存頁的大小就是空閑空間:

uint64 freemem(void) {
    struct run *r = kmem.freelist; uint64 n = 0;
    for (; r != 0; r = r->next) n += 4096;
    return n;
}

關於nproc函數,需要理解proc.c的內容了,這個文件主要進行進程的管理,xv6用一個數組來維護所有的進程,不管是在運行的、在等待的還是沒被分配的。所以nproc函數只需要遍歷這個數組數清有多少沒被分配的進程就行了:

uint64 nproc(void) {
    struct proc* p; uint64 n = 0;
    for(p = proc; p < &proc[NPROC]; p++) {
        acquire(&p->lock);
        if(p->state != UNUSED) n++;
        release(&p->lock);
    }
    return n;
}

總結一下,這次實驗我覺得設計得十分優秀,直擊系統調用的要點,而且也稍微涉及了物理內存管理和進程管理的內容,為后面的實驗打下基礎。實際上這次實驗是2020年版本的6.S081實驗才有的,以前的第二次實驗都是寫shell,私以為這個系統調用的實驗遠強於寫shell的實驗,shell實驗的主要技術點和實驗一基本上是重復的,而主要工作量則集中在字符串操作等繁瑣的地方,感覺這樣就舍本逐末了,我理想中優秀的實驗就應該是事半功倍,用最小的工作量,最清晰的操作指南幫助學生掌握最多的知識。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM