当前位置: 首页 > news >正文

100块钱开发网站seo的作用是什么

100块钱开发网站,seo的作用是什么,岳阳注册公司,做网站收入怎么样PgtblPrint a page tableA kernel page table per processSimplify copyin/copyinstr本Lab简单优化了系统的页表功能,使得程序在内核态时可以直接解析用户态的指针。笔者用时约8hPrint a page table 第一部分是为系统添加一个打印给定页表的函数vmprint&#xff0c…

Pgtbl

  • Print a page table
  • A kernel page table per process
  • Simplify copyin/copyinstr

本Lab简单优化了系统的页表功能,使得程序在内核态时可以直接解析用户态的指针。
笔者用时约8h

Print a page table

第一部分是为系统添加一个打印给定页表的函数vmprint,该函数接收一个参数pagetable(根页表的物理地址),递归遍历整张页表,打印有效的表项。
参考freewalk函数(定义在kernel/vm.c:331),每次遍历512个表项,若表项有效,则打印相关信息(第几级、第几项、pte内容和pte内容对应的物理地址),且若为一二级页表则继续递归,直到第三级页表返回。参考代码如下:

void 
vmprint_helper(pagetable_t pgtbl, int level) 
{// there are 2^9 = 512 PTEs in a page table.for(int i = 0; i < 512; i++){pte_t pte = pgtbl[i];if(pte & PTE_V){for (int j = 0; j < level; j ++ ) {if (j) printf(" ");printf("..");}printf("%d: pte %p pa %p\n", i, pte, PTE2PA(pte));if ((pte & (PTE_R|PTE_W|PTE_X)) == 0) {// this PTE points to a lower-level page table.uint64 child = PTE2PA(pte);vmprint_helper((pagetable_t)child, level + 1);}}}
}void
vmprint(pagetable_t pgtbl) 
{printf("page table %p\n", pgtbl);vmprint_helper(pgtbl, 1);
}

A kernel page table per process

如标题,第二部分的内容是为每一个进程添加一个单独的内核页表副本,为下一节直接解引用用户态指针做铺垫。

首先需要在进程的结构体(定义在kernel/proc.h中)struct proc中添加一个字段维护内核页表副本,如下图所示
在这里插入图片描述

然后,由于我们需要在分配进程时需要为每一个进程初始化一个内核页表的副本,于是需要参考kvminit函数(定义在kernel/vm.c:66),编写一个初始化进程中内核页表副本的函数proc_kvminit,代码如下所示。该函数内容与kvminit函数基本一致。其中的uvmmapkvmmap函数(定义在kernel/vm.c:171)类似,映射给定的虚拟地址和物理地址范围,唯一不同点是前者修改的是传入的指定页表而不仅仅是全局的内核页表。

void 
uvmmap(pagetable_t pagetable, uint64 va, uint64 pa, uint64 sz, int perm) 
{if(mappages(pagetable, va, sz, pa, perm) != 0)panic("uvmmap");
}/** create a direct-map page table for the given process.*/
pagetable_t
proc_kvminit() 
{pagetable_t pgtbl = (pagetable_t) kalloc();if (pgtbl == 0) return 0;memset(pgtbl, 0, PGSIZE);// uart registersuvmmap(pgtbl, UART0, UART0, PGSIZE, PTE_R | PTE_W);// virtio mmio disk interfaceuvmmap(pgtbl, VIRTIO0, VIRTIO0, PGSIZE, PTE_R | PTE_W);// CLINTuvmmap(pgtbl, CLINT, CLINT, 0x10000, PTE_R | PTE_W);// PLICuvmmap(pgtbl, PLIC, PLIC, 0x400000, PTE_R | PTE_W);// map kernel text executable and read-only.uvmmap(pgtbl, KERNBASE, KERNBASE, (uint64)etext-KERNBASE, PTE_R | PTE_X);// map kernel data and the physical RAM we'll make use of.uvmmap(pgtbl, (uint64)etext, (uint64)etext, PHYSTOP-(uint64)etext, PTE_R | PTE_W);// map the trampoline for trap entry/exit to// the highest virtual address in the kernel.uvmmap(pgtbl, TRAMPOLINE, (uint64)trampoline, PGSIZE, PTE_R | PTE_X);return pgtbl;
}

接着在allocproc函数(定义在kernel/proc.c:95)中调用上述定义的proc_kvminit函数,实现在进程分配时初始化进程中的内核页表副本。同时,还需要将procinit中对进程内核栈对应的页表项初始化代码段移动到allocproc函数中,如下所示。这里需要注意的是,原始代码中对进程context字段的修改一定要放在最下面。(暂时不知道为啥,等知道了再补一下原因)

  ...// initialize the process kernel page tablep->kernel_pagetable = proc_kvminit();if(p->kernel_pagetable == 0){freeproc(p);release(&p->lock);return 0;}// initialize the process kernel stack in kernel process kernel page tablechar *pa = kalloc();if(pa == 0)panic("kalloc");uint64 va = KSTACK((int) (p - proc));uvmmap(p->kernel_pagetable, va, (uint64)pa, PGSIZE, PTE_R | PTE_W);p->kstack = va;// Set up new context to start executing at forkret,// which returns to user space.memset(&p->context, 0, sizeof(p->context));p->context.ra = (uint64)forkret;p->context.sp = p->kstack + PGSIZE;return p;

接下来在scheduler函数(定义在kernel/proc.c:489)中,当调度进程执行时,将进程对应的内核页表加载到satp寄存器中,且调用sfence_vma进行刷新。在进程执行完,调用将页表切换回全局的内核页表,代码段如下所示。

    // load process's kernel page table and flush the TLBw_satp(MAKE_SATP(p->kernel_pagetable));sfence_vma();swtch(&c->context, &p->context);// load kernel page table when process donekvminithart();

最后,还需要在freeproc函数(定义在kernel/proc.c:155)中释放进程所维护的内核页表副本。需要将进程中内核页表维护的内核栈物理空间释放掉,调用uvmunmap函数(定义在kernel/vm.c:230)即可。同时还需要将维护的内核页表副本销毁掉,由于freewalk函数只销毁第一级和第二级页表表项,需要自己写一个类似的函数来销毁第三级页表的表项,如下所示。

// Recursively free process's kernel page-table pages.
void 
proc_freewalk(pagetable_t pagetable)
{// there are 2^9 = 512 PTEs in a page table.for(int i = 0; i < 512; i++){pte_t pte = pagetable[i];if((pte & PTE_V) && (pte & (PTE_R|PTE_W|PTE_X)) == 0){// this PTE points to a lower-level page table.uint64 child = PTE2PA(pte);proc_freewalk((pagetable_t)child);pagetable[i] = 0;} else if(pte & PTE_V){pagetable[i] = 0;}}kfree((void*)pagetable);
}

freeproc函数中的相关代码段如下

  // free process's kernel page tableuvmunmap(p->kernel_pagetable, p->kstack, 1, 1);p->kstack = 0;proc_freewalk(p->kernel_pagetable);p->kernel_pagetable = 0;

Simplify copyin/copyinstr

这一部分需要实现的是将每一个进程的用户空间映射添加到进程维护的内核页表副本中(上一节创建的),由于用户空间的虚拟地址从0开始,且内核的虚拟地址从较高的地址开始(文档里说是PLIC,但是xv6book里面的图3.3是从CLINT开始的,暂时不知道为啥),所以给用户空间的映射留下了一些虚拟空间进行映射(0~PLIC-1)。
我们需要在fork函数、exec函数、growproc函数与userinit函数中,为进程维护的内核页表添加上用户空间的映射,因为这些函数都更改了用户映射。

首先,我仿照uvmcopy函数(定义在kernel/vm.c:384),定义了一个函数uvm2ukvm,它接收两个页表,一个是用户进程页表,一个是用户进程中维护的内核页表,并接收需要映射的起始虚拟地址和末尾虚拟地址,将这个范围内的用户空间虚拟地址复制到进程维护的内核页表中。注意需要将PTE_U标志位置为0,否则内核无法访问。

void uvm2ukvm(pagetable_t upgtbl, pagetable_t ukpgtbl, uint64 st, uint64 ed)
{pte_t *pte_u, *pte_uk;uint64 pa, i;uint flags;for (i = st; i < ed; i += PGSIZE) {if((pte_u = walk(upgtbl, i, 0)) == 0)panic("uvm2ukvm: pte_u should exist");if((*pte_u & PTE_V) == 0)panic("uvm2ukvm: page not present");pa = PTE2PA(*pte_u);flags = PTE_FLAGS(*pte_u);flags &= (~PTE_U);if((pte_uk = walk(ukpgtbl, i, 1)) == 0)panic("uvm2ukvm: pte_uk should exist");*pte_uk = PA2PTE(pa) | flags;}
}

fork函数中(定义在kernel/proc.c:289),调用以上函数,添加一行代码即可。

  ...// Copy user memory from parent to child.if(uvmcopy(p->pagetable, np->pagetable, p->sz) < 0){freeproc(np);release(&np->lock);return -1;}np->sz = p->sz;uvm2ukvm(np->pagetable, np->kernel_pagetable, 0, np->sz);...

exec函数中(定义在kernel/exec.c:13),也是一样的添加上一行代码即可。

  ...// Commit to the user image.oldpagetable = p->pagetable;p->pagetable = pagetable;p->sz = sz;uvm2ukvm(p->pagetable, p->kernel_pagetable, 0, sz);p->trapframe->epc = elf.entry;  // initial program counter = mainp->trapframe->sp = sp; // initial stack pointerproc_freepagetable(oldpagetable, oldsz);...

growproc函数中,当申请增长内存时,需要判断增长后的虚拟地址上界是否超过PLIC的起始地址,如果超过则返回-1,否则也是调用上述函数将增长的地址范围复制一份到进程维护的内核页表中即可。

  ...if (PGROUNDUP(sz + n) > PLIC) {return -1;}if((sz = uvmalloc(p->pagetable, sz, sz + n)) == 0) {return -1;}uvm2ukvm(p->pagetable, p->kernel_pagetable, sz - n, sz);...

userinit函数中第一次初始化进程页表时,也要进行复制。

  ...// allocate one user page and copy init's instructions// and data into it.uvminit(p->pagetable, initcode, sizeof(initcode));uvm2ukvm(p->pagetable, p->kernel_pagetable, 0, PGSIZE);...

最后,把copyin函数和copyinstr函数体中的内容改成调用copyin_newcopyinstr_new函数即可。

http://www.lbrq.cn/news/2521837.html

相关文章:

  • 石家庄网站seo顾问青岛快速排名优化
  • 公司做网站关键词排名软件
  • 黄岛网站建设价格今日新闻最新
  • nh网站建设杭州正规引流推广公司
  • 国内做网站网站浏览器
  • 图标网站导航制作怎么做seo优化包括哪些内容
  • 全球网站排名济南网络推广网络营销
  • 商丘幼儿园网站建设策划方案自己怎样在百度上做推广
  • 公司是做小程序还是做网站厦门关键词优化网站
  • 代做一个网站多少钱淘宝流量平台
  • 下载网页制作设计编辑器软件百度app优化
  • 容桂网站建设找顺的整站优化seo平台
  • 福州建设人才网站软考十大最靠谱it培训机构
  • 跟做网站的人谈什么百度推广代理查询
  • 青海建设工程信息网站广东近期新闻
  • 注册安全工程师考试题库及答案百度推广的优化软件
  • cms网站建设方案智能营销方法
  • 开网站做一个交易所怎么做推广公司是做什么的
  • 做网站的专业南京市网站
  • 百度流量统计seo关键词首页排名
  • 招聘网站建设及推广免费行情网站大全搜狐网
  • 深圳网站建设收费标准南宁百度seo排名价格
  • 响应式网站的优缺点网页设计与制作知识点
  • 知名商城网站建设报价无锡seo关键词排名
  • 新闻网站怎么做缓存线上推广哪个平台最好
  • 项目建设目标北京seo排名优化网站
  • 大气机械网站属于seo网站优化
  • 台州网站建设多少钱引擎优化搜索
  • 南京网站建设费用软广告经典例子
  • 新建网站如何公安备案山东最新消息今天
  • RHCA学习概述
  • HTML应用指南:利用POST请求获取全国公牛门店位置信息
  • Java 笔记 封装(Encapsulation)
  • 电商项目_核心业务_分布式事务
  • SpringBoot 整合 自定义MongoDB
  • Python 程序设计讲义(46):组合数据类型——集合类型:集合间运算