中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當前位置: 首頁 > news >正文

網(wǎng)站是先備案 還是先做網(wǎng)站網(wǎng)站策劃書模板范文

網(wǎng)站是先備案 還是先做網(wǎng)站,網(wǎng)站策劃書模板范文,wordpress 后臺文章 查詢條件,施工企業(yè)成本管理在本實驗室中,您將探索頁表并對其進行修改,以簡化將數(shù)據(jù)從用戶空間復制到內(nèi)核空間的函數(shù)。 一、實驗準備 開始編碼之前,請閱讀xv6手冊的第3章和相關(guān)文件: kernel/memlayout.h,它捕獲了內(nèi)存的布局。kernel/vm.c&…

在本實驗室中,您將探索頁表并對其進行修改,以簡化將數(shù)據(jù)從用戶空間復制到內(nèi)核空間的函數(shù)。

一、實驗準備

開始編碼之前,請閱讀xv6手冊的第3章和相關(guān)文件:

  • kernel/memlayout.h,它捕獲了內(nèi)存的布局。
  • kernel/vm.c,其中包含大多數(shù)虛擬內(nèi)存(VM)代碼。
  • kernel/kalloc.c,它包含分配和釋放物理內(nèi)存的代碼。

可看這一篇博客來增加理解。

211.xv6——3(page tables)-CSDN博客

要啟動實驗,請切換到pgtbl分支:

$ git fetch
$ git checkout pgtbl
$ make clean

二、Print a page table (easy)

1.實驗要求

? ? ? ? 為了幫助您了解RISC-V頁表,也許為了幫助將來的調(diào)試,您的第一個任務(wù)是編寫一個打印頁表內(nèi)容的函數(shù)。

  1. 定義一個名為vmprint()的函數(shù)。
  2. 它應(yīng)當接收一個pagetable_t作為參數(shù),并以下面描述的格式打印該頁表。
  3. exec.c中的return argc之前插入if(p->pid==1) vmprint(p->pagetable),以打印第一個進程的頁表。
  4. 如果你通過了pte printout測試的make grade,你將獲得此作業(yè)的滿分。

現(xiàn)在,當您啟動xv6時,它應(yīng)該像這樣打印輸出來描述第一個進程剛剛完成exec()inginit時的頁表:

page table 0x0000000087f6e000
..0: pte 0x0000000021fda801 pa 0x0000000087f6a000
.. ..0: pte 0x0000000021fda401 pa 0x0000000087f69000
.. .. ..0: pte 0x0000000021fdac1f pa 0x0000000087f6b000
.. .. ..1: pte 0x0000000021fda00f pa 0x0000000087f68000
.. .. ..2: pte 0x0000000021fd9c1f pa 0x0000000087f67000
..255: pte 0x0000000021fdb401 pa 0x0000000087f6d000
.. ..511: pte 0x0000000021fdb001 pa 0x0000000087f6c000
.. .. ..510: pte 0x0000000021fdd807 pa 0x0000000087f76000
.. .. ..511: pte 0x0000000020001c0b pa 0x0000000080007000
  1. 第一行顯示vmprint的參數(shù)。之后的每行對應(yīng)一個PTE,包含樹中指向頁表頁的PTE。
  2. 每個PTE行都有一些“..”的縮進表明它在樹中的深度。
  3. 每個PTE行顯示其在頁表頁中的PTE索引、PTE比特位以及從PTE提取的物理地址。
  4. 不要打印無效的PTE。在上面的示例中,頂級頁表頁具有條目0和255的映射。
  5. 條目0的下一級只映射了索引0,該索引0的下一級映射了條目0、1和2。

您的代碼可能會發(fā)出與上面顯示的不同的物理地址。條目數(shù)和虛擬地址應(yīng)相同。

2.提示

  • 你可以將vmprint()放在kernel/vm.c
  • 使用定義在kernel/riscv.h末尾處的宏
  • 函數(shù)freewalk可能會對你有所啟發(fā)
  • vmprint的原型定義在kernel/defs.h中,這樣你就可以在exec.c中調(diào)用它了
  • 在你的printf調(diào)用中使用%p來打印像上面示例中的完成的64比特的十六進制PTE和地址

3.實現(xiàn)

(1)首先在kernel/vm.c中添加vmprint()函數(shù)

// 遞歸打印頁表的函數(shù)。
// pagetable是頁表,level表示當前遞歸的深度。
void 
_vmprint(pagetable_t pagetable, int level)
{// 遍歷頁表中的每一個PTE(頁表項)。for (int i = 0; i < 512; i++){pte_t pte = pagetable[i]; // 獲取當前的頁表項。if(pte & PTE_V) // 如果頁表項有效(存在)。{// 打印縮進,根據(jù)當前遞歸的深度level來決定。for (int j = 0; j < level; j++){if(j)printf(" ");printf("..");}uint64 child = PTE2PA(pte); // 獲取頁表項指向的物理地址。printf("%d: pte %p pa %p\n", i, pte, child); // 打印頁表項信息。// 如果不是葉子節(jié)點(沒有R/W/X權(quán)限),繼續(xù)遞歸打印下一級頁表。if((pte & (PTE_W | PTE_R | PTE_X)) == 0){_vmprint((pagetable_t)child, level + 1);}}}
}// 打印頁表的入口函數(shù)。
// pagetable是頁表的根。
void vmprint(pagetable_t pagetable)
{printf("page table %p\n", pagetable); // 打印頁表的根地址。_vmprint(pagetable, 1); // 從根頁表開始遞歸打印,初始深度為1。
}

(2)在kernel/defs.h中添加定義

(3)在kernel/exec.c中添加

4.測試結(jié)果

三、A kernel page table per process (hard)

? ? ? ? Xv6有一個單獨的用于在內(nèi)核中執(zhí)行程序時的內(nèi)核頁表。內(nèi)核頁表直接映射(恒等映射)到物理地址,也就是說內(nèi)核虛擬地址x映射到物理地址仍然是x。Xv6還為每個進程的用戶地址空間提供了一個單獨的頁表,只包含該進程用戶內(nèi)存的映射,從虛擬地址0開始。因為內(nèi)核頁表不包含這些映射,所以用戶地址在內(nèi)核中無效。因此,當內(nèi)核需要使用在系統(tǒng)調(diào)用中傳遞的用戶指針(例如,傳遞給write()的緩沖區(qū)指針)時,內(nèi)核必須首先將指針轉(zhuǎn)換為物理地址。本節(jié)和下一節(jié)的目標是允許內(nèi)核直接解引用用戶指針。

1.實驗要求

? ? ? ? 你的第一項工作是修改內(nèi)核來讓每一個進程在內(nèi)核中執(zhí)行時使用它自己的內(nèi)核頁表的副本。修改struct proc來為每一個進程維護一個內(nèi)核頁表,修改調(diào)度程序使得切換進程時也切換內(nèi)核頁表。對于這個步驟,每個進程的內(nèi)核頁表都應(yīng)當與現(xiàn)有的的全局內(nèi)核頁表完全一致。如果你的usertests程序正確運行了,那么你就通過了這個實驗。

? ? ? ? 閱讀本作業(yè)開頭提到的章節(jié)和代碼;了解虛擬內(nèi)存代碼的工作原理后,正確修改虛擬內(nèi)存代碼將更容易。頁表設(shè)置中的錯誤可能會由于缺少映射而導致陷阱,可能會導致加載和存儲影響到意料之外的物理頁存頁面,并且可能會導致執(zhí)行來自錯誤內(nèi)存頁的指令。

2.提示

  • struct proc中為進程的內(nèi)核頁表增加一個字段
  • 為一個新進程生成一個內(nèi)核頁表的合理方案是實現(xiàn)一個修改版的kvminit,這個版本中應(yīng)當創(chuàng)造一個新的頁表而不是修改kernel_pagetable。你將會考慮在allocproc中調(diào)用這個函數(shù)。
  • 確保每一個進程的內(nèi)核頁表都關(guān)于該進程的內(nèi)核棧有一個映射。在未修改的XV6中,所有的內(nèi)核棧都在procinit中設(shè)置。你將要把這個功能部分或全部的遷移到allocproc
  • 修改scheduler()來加載進程的內(nèi)核頁表到核心的satp寄存器(參閱kvminithart來獲取啟發(fā))。不要忘記在調(diào)用完w_satp()后調(diào)用sfence_vma()
  • 沒有進程運行時scheduler()應(yīng)當使用kernel_pagetable
  • freeproc中釋放一個進程的內(nèi)核頁表
  • 你需要一種方法來釋放頁表,而不必釋放葉子物理內(nèi)存頁面。
  • 調(diào)式頁表時,也許vmprint能派上用場
  • 修改XV6本來的函數(shù)或新增函數(shù)都是允許的;你或許至少需要在kernel/vm.ckernel/proc.c中這樣做(但不要修改kernel/vmcopyin.c,?kernel/stats.c,?user/usertests.c, 和user/stats.c
  • 頁表映射丟失很可能導致內(nèi)核遭遇頁面錯誤。這將導致打印一段包含sepc=0x00000000XXXXXXXX的錯誤提示。你可以在kernel/kernel.asm通過查詢XXXXXXXX來定位錯誤。

3.具體實現(xiàn)

本實驗主要是讓每個進程都有自己的內(nèi)核頁表,這樣在內(nèi)核中執(zhí)行時使用它自己的內(nèi)核頁表的副本。

(1)首先在kernel/proc.h里面的struct proc增加內(nèi)核頁表的字段,表示內(nèi)核態(tài)頁表。

(2)在vm.c中添加新的方法proc_kpt_init,該方法用于在allocproc?中初始化進程的內(nèi)核頁表。這個函數(shù)還需要一個輔助函數(shù)uvmmap,該函數(shù)和kvmmap方法幾乎一致,不同的是kvmmap是對Xv6的內(nèi)核頁表進行映射,而uvmmap將用于進程的內(nèi)核頁表進行映射。

//用于映射虛擬地址到物理地址
void uvmmap(pagetable_t pagetable,uint64 va,uint64 pa,uint64 sz,int perm)
{if(mappages(pagetable,va,sz,pa,perm)!=0){panic("uvmmap");}
}//用于初始化內(nèi)核頁表
pagetable_t ukvminit()
{pagetable_t kernelpt = uvmcreate();if(kernelpt==0)return 0;uvmmap(kernelpt, UART0, UART0, PGSIZE, PTE_R | PTE_W);uvmmap(kernelpt, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W);uvmmap(kernelpt, CLINT, CLINT, 0x10000, PTE_R | PTE_W);uvmmap(kernelpt, PLIC, PLIC, 0x400000, PTE_R | PTE_W);uvmmap(kernelpt, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X);uvmmap(kernelpt, (uint64)etext, (uint64)etext, PHYSTOP-(uint64)etext, PTE_R | PTE_W);uvmmap(kernelpt, TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X);return kernelpt;
}

(3)在?kernel/proc.c?中的?allocproc?函數(shù)里添加調(diào)用函數(shù)的代碼:

記得在?kernel/defs.h?添加函數(shù)聲明:pagetable_t ukvminit(void);

(4)在內(nèi)核棧的初始化原來是在?kernel/proc.c?中的?procinit?函數(shù)內(nèi),這部分要求將函數(shù)內(nèi)的代碼轉(zhuǎn)移到?allocproc?函數(shù)內(nèi),因此在上一步初始化內(nèi)核態(tài)頁表的代碼下面接著添加初始化內(nèi)核棧的代碼:

kvminithart是用于原先的內(nèi)核頁表,我們將進程的內(nèi)核頁表傳進去就可以。在vm.c里面添加一個新方法proc_inithart。

然后在scheduler()內(nèi)調(diào)用即可,但在結(jié)束的時候,需要切換回原先的kernel_pagetable。直接調(diào)用調(diào)用上面的kvminithart()就能把Xv6的內(nèi)核頁表加載回去。

(6)?在freeproc中釋放一個進程的內(nèi)核頁表。首先釋放頁表內(nèi)的內(nèi)核棧,調(diào)用uvmunmap可以解除映射,最后的一個參數(shù)(do_free)為一的時候,會釋放實際內(nèi)存。

// free the kernel stack in the RAM
uvmunmap(p->kernelpt, p->kstack, 1, 1);
p->kstack = 0;

然后釋放進程的內(nèi)核頁表,先在kernel/proc.c里面添加一個方法proc_freekernelpt。如下,歷遍整個內(nèi)核頁表,然后將所有有效的頁表項清空為零。如果這個頁表項不在最后一層的頁表上,需要繼續(xù)進行遞歸。

void proc_freekernelpt(pagetable_t kernelpt)
{// similar to the freewalk method// there are 2^9 = 512 PTEs in a page table.for (int i = 0; i < 512;i++){pte_t pte = kernelpt[i];if(pte&PTE_V){kernelpt[i] = 0;if((pte&(PTE_R|PTE_W|PTE_X))==0){uint64 child = PTE2PA(pte);proc_freekernelpt((pagetable_t)child);}}}kfree((void *)kernelpt);
}

(6). 將需要的函數(shù)定義添加到?kernel/defs.h?中

(7). 修改vm.c中的kvmpa,將原先的kernel_pagetable改成myproc()->kernelpt,使用進程的內(nèi)核頁表。

最后,在 vm.c 中添加頭文件:

#include "spinlock.h"
#include "proc.h"

最后修改kvmpa函數(shù)

uint64
kvmpa(uint64 va)
{uint64 off = va % PGSIZE;pte_t *pte;uint64 pa;pte = walk(myproc()->kernelpt, va, 0); // 修改這里if(pte == 0)panic("kvmpa");if((*pte & PTE_V) == 0)panic("kvmpa");pa = PTE2PA(*pte);return pa+off;
}

4.測試結(jié)果

四、Simplify copyin/copyinstr

? ? ? ? 內(nèi)核的copyin函數(shù)讀取用戶指針指向的內(nèi)存。它通過將用戶指針轉(zhuǎn)換為內(nèi)核可以直接解引用的物理地址來實現(xiàn)這一點。這個轉(zhuǎn)換是通過在軟件中遍歷進程頁表來執(zhí)行的。在本部分的實驗中,您的工作是將用戶空間的映射添加到每個進程的內(nèi)核頁表(上一節(jié)中創(chuàng)建),以允許copyin(和相關(guān)的字符串函數(shù)copyinstr)直接解引用用戶指針。

?1.實驗要求

  • 將定義在kernel/vm.c中的copyin的主題內(nèi)容替換為對copyin_new的調(diào)用(在kernel/vmcopyin.c中定義);
  • copyinstrcopyinstr_new執(zhí)行相同的操作。
  • 為每個進程的內(nèi)核頁表添加用戶地址映射,以便copyin_newcopyinstr_new工作。
  • 如果usertests正確運行并且所有make grade測試都通過,那么你就完成了此項作業(yè)。

? ? ? ? 此方案依賴于用戶的虛擬地址范圍不與內(nèi)核用于自身指令和數(shù)據(jù)的虛擬地址范圍重疊。Xv6使用從零開始的虛擬地址作為用戶地址空間,幸運的是內(nèi)核的內(nèi)存從更高的地址開始。然而,這個方案將用戶進程的最大大小限制為小于內(nèi)核的最低虛擬地址。內(nèi)核啟動后,在XV6中該地址是0xC000000,即PLIC寄存器的地址;請參見kernel/vm.c中的kvminit()、kernel/memlayout.h和文中的圖3-4。您需要修改xv6,以防止用戶進程增長到超過PLIC的地址。

2.提示

  • 先用對copyin_new的調(diào)用替換copyin(),確保正常工作后再去修改copyinstr
  • 在內(nèi)核更改進程的用戶映射的每一處,都以相同的方式更改進程的內(nèi)核頁表。包括fork(),?exec(), 和sbrk().
  • 不要忘記在userinit的內(nèi)核頁表中包含第一個進程的用戶頁表
  • 用戶地址的PTE在進程的內(nèi)核頁表中需要什么權(quán)限?(在內(nèi)核模式下,無法訪問設(shè)置了PTE_U的頁面)
  • 別忘了上面提到的PLIC限制

? ? ? ? Linux使用的技術(shù)與您已經(jīng)實現(xiàn)的技術(shù)類似。直到幾年前,許多內(nèi)核在用戶和內(nèi)核空間中都為當前進程使用相同的自身進程頁表,并為用戶和內(nèi)核地址進行映射以避免在用戶和內(nèi)核空間之間切換時必須切換頁表。然而,這種設(shè)置允許邊信道攻擊,如Meltdown和Spectre。

3.實現(xiàn)

? ? ? ? 本實驗是實現(xiàn)將用戶空間的映射添加到每個進程的內(nèi)核頁表,將進程的頁表復制一份到進程的內(nèi)核頁表就好。

? ? ? ? 首先添加復制函數(shù)。需要注意的是,在內(nèi)核模式下,無法訪問設(shè)置了PTE_U的頁面,所以我們要將其移除。

(1)復制頁表內(nèi)容

void u2kvmcopy(pagetable_t pagetable, pagetable_t kernelpt, uint64 oldsz, uint64 newsz) {pte_t *pte_from, *pte_to;// 將 oldsz 向上取整到最近的頁邊界oldsz = PGROUNDUP(oldsz);// 遍歷 [oldsz, newsz) 范圍內(nèi)的每一頁for (uint64 i = oldsz; i < newsz; i += PGSIZE) {// 從用戶頁表中獲取地址 i 對應(yīng)的 PTEif ((pte_from = walk(pagetable, i, 0)) == 0)panic("u2kvmcopy: src pte does not exist");// 確保用戶頁表中的頁表項是有效的(即包含 PTE_V 標志)if (!(*pte_from & PTE_V))panic("u2kvmcopy: src pte not valid");// 獲取或創(chuàng)建內(nèi)核頁表中地址 i 對應(yīng)的 PTEif ((pte_to = walk(kernelpt, i, 1)) == 0)panic("u2kvmcopy: pte walk failed");// 從用戶頁表項中獲取物理地址uint64 pa = PTE2PA(*pte_from);// 從用戶頁表項中獲取標志,并移除用戶權(quán)限標志 PTE_Uuint flags = (PTE_FLAGS(*pte_from)) & (~PTE_U);// 設(shè)置內(nèi)核頁表項*pte_to = PA2PTE(pa) | flags;}
}

第二步,fork(),sbrk(),exec()

然后在內(nèi)核更改進程的用戶映射的每一處 (fork(),?exec(), 和sbrk()),都復制一份到進程的內(nèi)核頁表。

fork()

exec()

sbrk(),?在kernel/sysproc.c里面找到sys_sbrk(void),可以知道只有growproc是負責將用戶內(nèi)存增加或縮小 n 個字節(jié)。以防止用戶進程增長到超過PLIC的地址,我們需要給它加個限制。

然后替換掉原有的copyin()copyinstr()

// Copy from user to kernel.
// Copy len bytes to dst from virtual address srcva in a given page table.
// Return 0 on success, -1 on error.
int
copyin(pagetable_t pagetable, char *dst, uint64 srcva, uint64 len)
{return copyin_new(pagetable, dst, srcva, len);
}// Copy a null-terminated string from user to kernel.
// Copy bytes to dst from virtual address srcva in a given page table,
// until a '\0', or max.
// Return 0 on success, -1 on error.
int
copyinstr(pagetable_t pagetable, char *dst, uint64 srcva, uint64 max)
{return copyinstr_new(pagetable, dst, srcva, max);
}

并且添加到?kernel/defs.h?中

// vmcopyin.c
int             copyin_new(pagetable_t, char *, uint64, uint64);
int             copyinstr_new(pagetable_t, char *, uint64, uint64);

http://www.risenshineclean.com/news/1812.html

相關(guān)文章:

  • 外貿(mào)平臺有哪些分別對應(yīng)哪個市場隨州seo
  • 網(wǎng)站建設(shè) 外包南寧百度快速排名優(yōu)化
  • 南通市網(wǎng)站建設(shè)我的完廣州網(wǎng)絡(luò)營銷推廣
  • 做銀行設(shè)計有好的網(wǎng)站參考嗎網(wǎng)站搭建需要多少錢
  • 溫州多語言網(wǎng)站建設(shè)網(wǎng)站發(fā)帖推廣平臺
  • 網(wǎng)頁瀏覽設(shè)置在哪里打開網(wǎng)頁優(yōu)化
  • 做網(wǎng)站比較好的環(huán)球網(wǎng)疫情最新
  • 2015做哪個網(wǎng)站能致富沈陽專業(yè)seo關(guān)鍵詞優(yōu)化
  • 建設(shè)公司企業(yè)網(wǎng)站個人網(wǎng)頁怎么制作
  • WordPress網(wǎng)頁加載時間seo網(wǎng)站優(yōu)化快速排名軟件
  • 備案名 網(wǎng)站名互聯(lián)網(wǎng)營銷師教材
  • 有幾個網(wǎng)站能在百度做推廣怎么弄推廣廣告
  • 手機門戶網(wǎng)站百度推廣賬戶登錄首頁
  • 城鄉(xiāng)與建設(shè)部網(wǎng)站首頁seo工具不包括
  • 購物網(wǎng)站英語濟南做seo的公司排名
  • wordpress鏈接亞馬遜在線優(yōu)化工具
  • 云南省網(wǎng)站備案要求網(wǎng)絡(luò)推廣企劃
  • 長沙市住建委和城鄉(xiāng)建設(shè)網(wǎng)站長沙網(wǎng)絡(luò)公司排名
  • WordPress圖片置頂寧波seo在線優(yōu)化
  • 友點企業(yè)網(wǎng)站管理系統(tǒng)模板下載百度如何優(yōu)化排名靠前
  • 搜索的網(wǎng)站后大拇指分享數(shù)量不見了收錄批量查詢工具
  • 2017年網(wǎng)站設(shè)計磁力貓引擎
  • 上海專業(yè)做網(wǎng)站公司電話注冊域名費用一般多少錢
  • 手機怎么制作釣魚網(wǎng)站網(wǎng)絡(luò)營銷組織的概念
  • 大公司做網(wǎng)站seo分析
  • 用什么做視頻網(wǎng)站比較好個人在百度上發(fā)廣告怎么發(fā)
  • 大型門戶網(wǎng)站建設(shè)包括哪些方面seoapp推廣
  • 上海網(wǎng)站建設(shè)推薦今日新聞頭條最新消息
  • 注冊了域名怎么做網(wǎng)站成全在線觀看免費高清動漫
  • 做炫舞情侶頭像動態(tài)圖網(wǎng)站推廣是什么意思