xv6操作系统源码阅读之页表

硬件支持

在这里插入图片描述
如上图,对于x86硬件来说,其在寻址时(保护模式下),会通过CR3寄存器找到页目录表的地址,接着虚拟地址的高十位会作为页目录表的索引,从而找到对应的页表,接着虚拟地址的中间10个bit会被作为页表中的索引,从而找到对应的页的物理地址,最后虚拟地址的低12位被用来指示其在页中的偏移,由于偏移量占了12位,也就意味着每一个页的大小为4k个字节。
页目录表和页表都有1024条记录,这些记录的高20位对应的就是分配的物理地址,低12位为一些标志位,比如P标志位指示了当前该虚拟地址是否分配了物理地址,如果为0,则会产生错误(陷入中断),再比如U标志位指示了用户进程是否允许访问该页表,如果为0,则该页表项只能由内核访问。由于页目录表中和页表中每一项占32bit,所以每个页目录表和页表的大小也就为4096个字节。

进程地址空间

在这里插入图片描述

如上图,进程的地址空间从0地址一直到KERNBASE,再往上就是内核空间。上图中的各个宏的定义代码如下。

// Memory layout

#define EXTMEM  0x100000            // Start of extended memory
#define PHYSTOP 0xE000000           // Top physical memory
#define DEVSPACE 0xFE000000         // Other devices are at high addresses

// Key addresses for address space layout (see kmap in vm.c for layout)
#define KERNBASE 0x80000000         // First kernel virtual address
#define KERNLINK (KERNBASE+EXTMEM)  // Address where kernel is linked

根据KERNBASE的值可以判断出每个进程所能使用的空间有2GB。
从上图中可以看出内核把自己映射到了0到PHYSTOP的物理地址,PHYSTOP代表物理地址的上限,但是由于内核部分的虚拟空间只有2GB,这也使得即使PHYSTOP大于2GB,也就是说物理内存大于2GB,内核也使用不了,因为物理空间超过了其虚拟空间的大小。
一些内存映射IO设备的物理地址从0xFE000000开始,所以虚拟地址直接映射过去就可以了。
另外内核部分的页表的U标志是清零的,这也代表内核空间是不允许用户进程访问的。
由于每个进程的地址空间都包含了内核和用户两部分,这也使得从用户空间切换到内核空间不需要进行页表的切换。

创建地址空间源码分析

在之前的源码分析系列文章中我们看到了给内核分配地址空间的是kvmalloc函数,其实也就是建立KERNBASE以上虚拟地址的映射,代码如下。

// Allocate one page table for the machine for the kernel address
// space for scheduler processes.
void
kvmalloc(void)
{
   
  kpgdir = setupkvm();
  switchkvm();
}

可以看到其主要是调用了setupkvm函数,代码如下。

// Set up kernel part of a page table.
pde_t*
setupkvm(void)
{
   
  pde_t *pgdir;
  struct kmap *k;

  if((pgdir = (pde_t*)kalloc()) == 0)
    return 0;
  memset(pgdir, 0, PGSIZE);
  if (P2V(PHYSTOP) > (void*)DEVSPACE)
    panic("PHYSTOP too high");
  for(k = kmap; k < &kmap[NELEM(kmap)]; k++)
    if(mappages(pgdir, k->virt, k->phys_end - k->phys_start,
                (uint)k->phys_start, k->perm) < 0) {
   
      freevm(pgdir);
      return 0;
    }
  return pgdir;
}

setupkvm函数主要是对内核部分的进程地址空间进行映射,代码定义如下。

static struct kmap {
   
  void *virt;
  uint phys_start;
  uint phys_end;
  int perm;
} kmap[] = {
   
 {
    (void*)KERNBASE, 0,             EXTMEM,    PTE_W}, // I/O space
 {
    (void*)KERNLINK, V2P(KERNLINK), V2P(data), 0},     // kern text+rodata
 {
    (void*)data,     V2P
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值