从C中的虚拟地址计算物理地址

时间:2015-06-05 04:24:35

标签: c virtual-memory

我正努力编写一个将虚拟内存地址转换为物理内存地址的函数。我希望该函数返回虚拟16位地址的物理内存地址。

我只使用忽略权限位(读,写等)的16位长虚拟地址。页表中有256页,因此基表寄存器(即BTR)只指向表。

我希望函数返回:

    Success: the physical address (a void*)
    Page Fault: the virtual page number (an integer)
    Protection Fault: a copy of the PTE

这是页表条目:

    31    30..28 27..............................................4 3 2 1 0
   +-----+------+-------------------------------------------------+-+-+-+-+
   |Valid|unused| 24-bit Physical Page Number                     |P|R|W|X|
   +-----+------+-------------------------------------------------+-+-+-+-+

我试图了解虚拟内存的工作原理。我对如何获取16位虚拟地址并将其映射到32位页表条目以及如何从那里获取物理地址感到困惑。我已经定义了result_t以及下面的页表条目的联合,但我不确定如何使用它们。我在线查看得到了很多帮助,但一切都变得混乱,我只是想了解一切如何直截了当。

以下是一些必要的定义:  

  extern void* BTR;

  typedef struct result_st {
     enum {SUCCESS, PAGEFAULT,
                PROTFAULT, NOTIMPLEMENTED} status;
     union {
         void* pa;
         unsigned vpn;
         unsigned pte;
     } value;

    } result_t;
  static result_t success(void* pa) {

      result_t res;
      res.status=SUCCESS;
      res.value.pa = pa;
      return res;
    }

  typedef union {
      unsigned All;
      struct {
        unsigned Valid               :1;
        unsigned Unused              :3;
        unsigned PhysicalPageNumber  :24;
        unsigned SupervisoryMode     :1;
        unsigned Read                :1;
        unsigned Execute             :1;
        unsigned Write               :1;

      };
    } PageTableEntry;

  static int is_valid (unsigned pte) {

        return 1 & (pte >> 31);
      }

这是我写的函数:

result_t legacy(unsigned short va)
{
  result_t result;
  unsigned pte = va << 8;
  result.value.pte = pte;
  // This is my attempt so far.
  // I want to use is_Valid() somewhere

  void* pa = pte >> 8 | (va & 255);
    return success(pa);
}

感谢您提供任何建议!

1 个答案:

答案 0 :(得分:0)

您缺少实际页面表的定义。我认为它是这样的(假设我已正确理解你的问题):

#define PAGE_TABLE_SIZE 256
PageTable page_table[PAGE_TABLE_SIZE];

然后你的代码看起来像这样:

#define VIRT_PAGE_SIZE_BITS 8

/* Get virtual page number by dividing by the virt page size */
unsigned int virt_page_num = va >> VIRT_PAGE_SIZE_BITS;

assert(virt_page_num < PAGE_TABLE_SIZE); // Or do proper error handling

/* Use virtual page number to index into page table */
PageTableEntry pte = page_table[virt_page_num];
if (is_valid(pte)) {
    if (is_access_ok(pte)) {
        unsigned int phys_page_num = pte.PhysicalPageNumber;
        return success(phys_page_num);
    } else {
        /* Protection fault code goes here */
    }
} else {
    /* Page fault code goes here */
}