简体   繁体   English

C 虚拟到物理地址映射

[英]C Virtual to physical address mapping

I am beginner in C, I am trying to convert virtual addresses to physical.我是 C 的初学者,我正在尝试将虚拟地址转换为物理地址。

My code so far, but don't know how to the translation.我的代码到目前为止,但不知道如何翻译。

I am using 4Kb pages.我正在使用4Kb页面。

The conversion I know is: for givin address: 0x12C000, the last three numbers won't be changed 000 and the remaining 12C will be converted, and then combine the fixed numbers with the converted.我知道的转换是:对于给定地址:0x12C000,最后三个数字不会变成000,其余的12C将被转换,然后将固定数字与转换后的数字结合起来。 correct me if wrong, and how do I do taht in code?如果错了,请纠正我,我该如何在代码中做到这一点?

#include <stdio.h>

int main() {

    uint page_table[512] = { 0 };
    page_table[200] = 0x1234;
    page_table[300] = 0x2345 ;
    page_table[511] = 0x8000 ;

    uint page_table_size = (sizeof(array)/sizeof(array[0]));
    uint page_size_bits 12 // // 2^12 = 4KB;
    uint mask_offset ((1<<page_size_bits)-1);

    // example of correct outputs:

    uint log_addr = 0x12C000;

    /* should be 0x2345000 */
    uint correctoutput; 

    log_addr = 0x12CFFF;

    /* should be 0x2345FFF */
    correctoutput; 

    log_addr = 0x1FF84A;

    /* should be 0x800084A */
    correctoutput; 

}

Unless you are running in a privileged mode of the CPU, which usually means you are in the kernel you can't.除非你在 CPU 的特权模式下运行,这通常意味着你在 kernel 中你不能。 The OS + CPU team up to prevent you from accessing the page tables, and the only way you could do this is by accessing the page tables. OS + CPU 联手阻止您访问页表,而您可以做到这一点的唯一方法是访问页表。

If you did have access to them, and you were a 32bit 386 program running without PAE, it would look something like this:如果您确实可以访问它们,并且您是一个没有 PAE 运行的 32 位 386 程序,它看起来像这样:

extern void *mapphys(unsigned pa);
extern unsigned getcr3(void);
unsigned vtop(unsigned va) {
       unsigned *pt, t;
       pt = mapphys(getcr3());
       t = pdir[va>>22];
       unmapphys(pt);
       if (t & 1) {
            pt = mapphys(t & ~ 0xfff);
            t  = pt[(va >> 12) & 0x3ff];
            unmapphys(pt);
            if (t & 1) {
                return (t &~ 0xfff) | (va & 0xfff);
            }
            error("page table entry undefined for %#x\n", va);
            return -1;
       } else {
            error("page directory entry undefined for %#x\n", va);
            return -2;
       }
}

where maphys, unmapphys provide and remove a usable pointer to the given physical address, and getcr3() returns the page table base register from the 386. That said, there are ways of constructing these sorts of page tables so that you can indirectly address them.其中 maphys、unmapphys 提供和删除指向给定物理地址的可用指针,getcr3() 从 386 返回页表基址寄存器。也就是说,有一些方法可以构建这些类型的页表,以便您可以间接寻址它们. For example, if you made the last (index 1023) entry in the page directory table point at the page directory table, then you can using the high 4M-4K of address space as a sort of page table map;例如,如果您将页目录表中的最后一个(索引 1023)条目指向页目录表,那么您可以使用地址空间的高 4M-4K 作为一种页表 map; and the final 4K of address space is a map of the page directory itself.最后4K的地址空间是页面目录本身的map。 With this setup, I can instead:使用此设置,我可以改为:

unsigned vtop(unsigned va) {
      unsigned *pmap = (unsigned *)0xff800000;
      unsigned *pdmap = (unsigned *)0xfffff000;
      if (pdmap[va>>22] & 1) {
          if (pmap[va>>12] & 1) {
               return (pmap[va>>12]&~0xfff) | (va & 0xfff);
          }
          error("page table entry undefined for %#x\n, va);
          return -1;
      }
      error("page dir entry undefined for %#x\n", va);
      return -2;
}

It is worth noting that in this recursive page table, which index you choose is not important, and the mechanism is generally applicable to any page table definition which is the interior and leaf nodes have compatible layouts.值得注意的是,在这个递归页表中,选择哪个索引并不重要,该机制一般适用于任何内部和叶节点布局兼容的页表定义。

You need to calculate two values: The index into the physical memory (page_table) and the offset to add to the page_table entries address.您需要计算两个值:物理 memory (page_table) 的索引和添加到 page_table 条目地址的偏移量。

page_table_index = log_address >> 12;
page_offset = log_address & 0xfff;
physical = (page_table[page_table_index] << 12) | page_offset;

The lower 12 bits are the offset.低 12 位是偏移量。 You keep that part of the address.你保留地址的那部分。 You shift these 12 bits off and you are left with the page number in the page_table array.您将这 12 位移开,剩下的就是 page_table 数组中的页码。 You can then look up the page_table to obtain the base address, make space for the 12 bits in that address and insert the offset.然后,您可以查找 page_table 以获取基地址,为该地址中的 12 位腾出空间并插入偏移量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM