ucore lab3及challenge

练习1:给未被映射的地址映射上物理页

page_fault函数不知道哪些是“合法”的虚拟页,原因是ucore还缺少一定的数据结构来描述这种不在物理内存中的“合法”虚拟页。为此ucore通过建立mm_struct和vma_struct数据结构,描述了ucore模拟应用程序运行所需的合法内存空间。

当访问内存产生page fault异常时,可获得访问的内存的方式(读或写)以及具体的虚拟内存地址,这样ucore就可以查询此地址,看是否属于vma_struct数据结构中描述的合法地址范围中,如果在,则可根据具体情况进行请求调页/页换入换出处理;如果不在,则报错。

虚拟地址空间和物理地址空间的示意图:

在这里插入图片描述

注释中介绍了mm_struct(mm)vma_struct(vma)

/* 
  vmm design include two parts: mm_struct (mm) & vma_struct (vma)
  mm is the memory manager for the set of continuous virtual memory  
  area which have the same PDT. vma is a continuous virtual memory area.
  There a linear link list for vma & a redblack link list for vma in mm.
---------------
  mm related functions:
   golbal functions
     struct mm_struct * mm_create(void)
     void mm_destroy(struct mm_struct *mm)
     int do_pgfault(struct mm_struct *mm, uint32_t error_code, uintptr_t addr)
--------------
  vma related functions:
   global functions
     struct vma_struct * vma_create (uintptr_t vm_start, uintptr_t vm_end,...)
     void insert_vma_struct(struct mm_struct *mm, struct vma_struct *vma)
     struct vma_struct * find_vma(struct mm_struct *mm, uintptr_t addr)
   local functions
     inline void check_vma_overlap(struct vma_struct *prev, struct vma_struct *next)
---------------
   check correctness functions
     void check_vmm(void);
     void check_vma_struct(void);
     void check_pgfault(void);
*/

vma_struct:用于管理应用程序的虚拟内存,是描述应用程序对虚拟内存“需求”的结构

// the virtual continuous memory area(vma), [vm_start, vm_end), 
// addr belong to a vma means  vma.vm_start<= addr <vma.vm_end 
struct vma_struct {
   
    struct mm_struct *vm_mm; // the set of vma using the same PDT 
    uintptr_t vm_start;      // vma的开始地址      
    uintptr_t vm_end;        // vma的结束地址,不包括vm_end本身
    uint32_t vm_flags;       // flags of vma(包括可读、可写、可执行)
    list_entry_t list_link;  
  // linear list link which sorted by start addr of vma
};
//vm_flags
#define VM_READ                 0x00000001
#define VM_WRITE                0x00000002
#define VM_EXEC                 0x00000004

mm_struct

// the control struct for a set of vma using the same PDT
struct mm_struct {
   
    list_entry_t mmap_list;        
  // linear list link which sorted by start addr of vma
    struct vma_struct *mmap_cache; 
  // current accessed vma, used for speed purpose
  //指向当前正在使用的虚拟内存空间
    pde_t *pgdir;                  // 指向的mm_struct数据结构所维护的一级页表
    int map_count;                 // 记录mmap_list里面链接的vma_struct的个数
    void *sm_priv;   
  	// 指向用来链接记录页访问情况的链表头。(用于FIFO替换策略的访问。)
};

当启动分页机制以后,如果一条指令或数据的虚拟地址所对应的物理页框不在内存中或者访问的类型有错误(比如写一个只读页或用户态程序访问内核态的数据等),就会发生页访问异常。产生页访问异常的原因主要有:

  • 目标页帧不存在(页表项全为0,即该线性地址与物理地址尚未建立映射或者已经撤销);
  • 相应的物理页帧不在内存中(页表项非空,但Present标志位=0,比如在swap分区或磁盘文件上),这在本次实验中会出现,我们将在下面介绍换页机制实现时进一步讲解如何处理;
  • 不满足访问权限(此时页表项P标志=1,但低权限的程序试图访问高权限的地址空间,或者有程序试图写只读页面).

当出现上面情况之一,那么就会产生页面page fault(#PF)异常。
CPU会把产生异常的线性地址存储在CR2中,并且把表示页访问异常类型的值(简称页访问异常错误码,errorCode)保存在中断栈中。

do_pgfault()的调用关系图:

在这里插入图片描述

do_pgfault()函数从CR2寄存器中获取页错误异常的虚拟地址,根据error code来查找这个虚拟地址是否在某一个VMA的地址范围内,并且具有正确的权限。如果满足上述两个要求,则需要为分配一个物理页。
所以出现page fault后,会有一个中断状态指针tf,传到trap()中处理:

void
trap(struct trapframe *tf) {
   
    // dispatch based on what type of trap occurred
    trap_dispatch(tf);
}

调用trap_dispatch():

static void
trap_dispatch(struct trapframe *tf) {
   
    char c;

    int ret;

    switch (tf->tf_trapno) {
   
    case T_PGFLT:  //page fault页访问错误
        if ((ret = pgfault_handler(tf)) != 0) {
   
            print_trapframe(tf);
            panic("handle pgfault failed. %e\n", ret);
        }
        break;

因为此时应该是page fault,所以调用pgfault_handler()

static int
pgfault_handler(struct trapframe *tf) {
   
    extern struct mm_struct *check_mm_struct;
    print_pgfault(tf);
    if (check_mm_struct != NULL) {
   
        return do_pgfault(check_mm_struct, tf->tf_err, rcr2());
    }
    //CR2存储了产生异常的线性地址
    panic("unhandled page fault.\n");
}

然后调用了do_pgfault()。这和调用关系图完全吻合。

完成do_pgfault()函数:

int
do_pgfault(struct mm_struct *mm, uint32_t error_code, uintptr_t addr) {
   
    int ret = -E_INVAL;
    //try to find a vma which include addr
    //尝试寻找包括addr的vma
    struct vma_struct *vma = find_vma(mm, addr);

    pgfault_num++;
    //If the addr is in the range of a mm's vma?
    if (vma == NULL || vma->vm_start > addr) {
   
        cprintf("not valid addr %x, and  can not find it in vma\n", addr);
        goto failed;
    }
    //check the error_code
    switch (error_code & 3) {
   //错误处理
    default:
           /* error code flag : default is 3 ( W/R=1, P=1): write, present */
    case 2: /* error code flag : (W/R=1, P=0): write, not present */
        if (!(vma->vm_flags & VM_WRITE)) {
   
            cprintf("do_pgfault failed: error code flag = write AND not present, but the addr's vma cannot write\n");
            goto failed;
        }
        break;
    case 1: /* error code flag : (W/R=0, P=1): read, present */
        cprintf("do_pgfault failed: error code flag = read AND present\n");
        goto failed;
        //如果无法读取直接报错
    case 0: /* error code flag : (W/R=0, P=0): read, not present */
        if (!(vma->vm_flags 
  • 5
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值