Exercise1 源代码阅读

  1. 内存管理部分: kalloc.c vm.c 以及相关其他文件代码
  • kalloc.c:char * kalloc(void)负责在需要的时候为用户空间、内核栈、页表页以及缓冲区分配物理内存,将物理地址转为虚拟地址返回,物理页大小为4k。void kfree(char * v)接收一个虚拟地址,找对对应的物理地址进行释放。xv6使用空闲内存的前部分作为指针域来指向下一页空闲内存,物理内存管理是以页(4K)为单位进行分配的。物理内存空间上空闲的每一页,都有一个指针域(虚拟地址)指向下一个空闲页,最后一个空闲页为NULL ,通过这种方式,kmem只需要保存着虚拟地址空间上的freelist地址即可;
// kalloc.c
// Physical memory allocator, intended to allocate
// memory for user processes, kernel stacks, page table pages,
// and pipe buffers. Allocates 4096-byte pages.void freerange(void *vstart, void *vend);
extern char end[]; // first address after kernel loaded from ELF filestruct run {struct run *next;
};struct {struct spinlock lock;int use_lock;struct run *freelist;
} kmem;
  • xv6让每个进程都有独立的页表结构,在切换进程时总是需要切换页表,switchkvm设置cr3寄存器的值为kpgdir首地址,kpgdir仅仅在scheduler内核线程中使用。页表和内核栈都是每个进程独有的,xv6使用结构体proc将它们统一起来,在进程切换的时候,他们也往往随着进程切换而切换,内核中模拟出了一个内核线程,它独占内核栈和内核页表kpgdir,它是所有进程调度的基础。switchuvm通过传入的proc结构负责切换相关的进程独有的数据结构,其中包括TSS相关的操作,然后将进程特有的页表载入cr3寄存器,完成设置进程相关的虚拟地址空间环境;
// vm.c……// Switch h/w page table register to the kernel-only page table,
// for when no process is running.
void
switchkvm(void)
{lcr3(v2p(kpgdir));   // switch to the kernel page table
}// Switch TSS and h/w page table to correspond to process p.
void
switchuvm(struct proc *p)
{pushcli();cpu->gdt[SEG_TSS] = SEG16(STS_T32A, &cpu->ts, sizeof(cpu->ts)-1, 0);cpu->gdt[SEG_TSS].s = 0;cpu->ts.ss0 = SEG_KDATA << 3;cpu->ts.esp0 = (uint)proc->kstack + KSTACKSIZE;ltr(SEG_TSS << 3);if(p->pgdir == 0)panic("switchuvm: no pgdir");lcr3(v2p(p->pgdir));  // switch to new address spacepopcli();
}
  • 进程的页表在使用前往往需要初始化,其中必须包含内核代码的映射,这样进程在进入内核时便不需要再次切换页表,进程使用虚拟地址空间的低地址部分,高地址部分留给内核,主要接口:

    • pde_t * setupkvm(void)通过kalloc分配一页内存作为页目录,然后将按照kmap数据结构映射内核虚拟地址空间到物理地址空间,期间调用了工具函数mappages;
    • int allocuvm(pde_t * pgdir, uint oldsz, uint newsz)在设置页表的同时分配虚拟地址oldsz到newsz的以页为单位的内存;
    • int deallocuvm(pde_t * pgdir, uint oldsz, uint newsz)则将newsz到oldsz对应的虚拟地址空间内存置为空闲;
    • int loaduvm(pde_t * pgdir, char * addr, struct inode * ip, uint offset, uint sz)将文件系统上的i节点内容读取载入到相应的地址上,通过allocuvm接口为用户进程分配内存和设置页表,然后调用loaduvm接口将文件系统上的程序载入到内存,便能够为exec系统调用提供接口,为用户进程的正式运行做准备;
    • 当进程销毁需要回收内存时,调用void freevm(pde_t * pgdir)清除用户进程相关的内存环境,其首先调用将0到KERNBASE的虚拟地址空间回收,然后销毁整个进程的页表;
    • pde_t * copyuvm(pde_t * pgdir, uint sz)负责复制一个新的页表并分配新的内存,新的内存布局和旧的完全一样,xv6使用这个函数作为fork()底层实现。

Exercise2 带着问题阅读

  1. XV6初始化之后到执行main.c时,内存布局是怎样的(其中已有哪些内容)?
  • 内核代码存在于物理地址低地址的0x100000处,页表为main.c文件中的entrypgdir数组,其中虚拟地址低4M映射物理地址低4M,虚拟地址 [KERNBASE, KERNBASE+4MB) 映射到 物理地址[0, 4MB);

  • 紧接着调用kinit1初始化内核末尾到物理内存4M的物理内存空间为未使用,然后调用kinit2初始化剩余内核空间到PHYSTOP为未使用。kinit1调用前使用的还是最初的页表(也就是是上面的内存布局),所以只能初始化4M,同时由于后期再构建新页表时也要使用页表转换机制来找到实际存放页表的物理内存空间,这就构成了自举问题,xv6通过在main函数最开始处释放内核末尾到4Mb的空间来分配页表,由于在最开始时多核CPU还未启动,所以没有设置锁机制。kinit2在内核构建了新页表后,能够完全访问内核的虚拟地址空间,所以在这里初始化所有物理内存,并开始了锁机制保护空闲内存链表;

  • 然后main函数通过调用void kvmalloc(void)函数来实现内核新页表的初始化;

  • 最后内存布局和地址空间如下:内核末尾物理地址到物理地址PHYSTOP的内存空间未使用,虚拟地址空间KERNBASE以上部分映射到物理内存低地址相应位置。

// kalloc.c
// Initialization happens in two phases.
// 1. main() calls kinit1() while still using entrypgdir to place just
// the pages mapped by entrypgdir on free list.
// 2. main() calls kinit2() with the rest of the physical pages
// after installing a full page table that maps them on all cores.
void
kinit1(void *vstart, void *vend)
{initlock(&kmem.lock, "kmem");kmem.use_lock = 0;freerange(vstart, vend);
}void
kinit2(void *vstart, void *vend)
{freerange(vstart, vend);kmem.use_lock = 1;
}// kmap.c
……
// This table defines the kernel's mappings, which are present in
// every process's page table.
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(data),     PHYSTOP,   PTE_W}, // kern data+memory{ (void*)DEVSPACE, DEVSPACE,      0,         PTE_W}, // more devices
};
……
  1. XV6 的动态内存管理是如何完成的? 有一个kmem(链表),用于管理可分配的物理内存页。(vend=0x00400000,也就是可分配的内存页最大为4Mb)
    详见“Exercise 1 源代码阅读”部分,已经作出完整解答。

  2. XV6的虚拟内存是如何初始化的? 画出XV6的虚拟内存布局图,请说出每一部分对应的内容是什么。见memlayout.h和vm.c的kmap上的注释?

  • main函数通过调用void kinit1(void * vstart, void * vend), void kinit2(void * vstart, void * vend), void kvmalloc(void)函数来实现内核新页表的初始化。虚拟地址与物理地址的转换接口:
// memlayout.h
// 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#ifndef __ASSEMBLER__static inline uint v2p(void *a) { return ((uint) (a))  - KERNBASE; }
static inline void *p2v(uint a) { return (void *) ((a) + KERNBASE); }#endif#define V2P(a) (((uint) (a)) - KERNBASE)
#define P2V(a) (((void *) (a)) + KERNBASE)#define V2P_WO(x) ((x) - KERNBASE)    // same as V2P, but without casts
#define P2V_WO(x) ((x) + KERNBASE)    // same as V2P, but without casts
  • 内存布局:

  1. 关于XV6 的内存页式管理。发生中断时,用哪个页表? 一个内存页是多大? 页目录有多少项? 页表有多少项? 最大支持多大的内存? 画出从虚拟地址到物理地址的转换图。在XV6中,是如何将虚拟地址与物理地址映射的(调用了哪些函数实现了哪些功能)?
  • 发生中断时,将换入cpu的进程的页表首地址存入cr3寄存器;一个内存页为4k;XV6页表采用的二级目录,一级目录有 2 10 2^{10} 210条,二级目录有 2 10 ∗ 2 10 2^{10} * 2^{10} 210∗210条;页表项为 2 2 2^2 22Bytes,故页表有 2 12 / 2 2 = 2 10 = 1024 2^{12} / 2^2 = 2^{10} = 1024 212/22=210=1024项;最大支持4G内存;

  • 物理内存页的申请与释放,虚拟地址与物理地址如何映射等在“Exercise 1 源代码阅读”都已经详述了,在此主要说下mappages接口,虚拟地址 * va与物理地址 * pa映射size个字节,同时赋予该页的权限perm,如下:
// vm.c
……
// Create PTEs for virtual addresses starting at va that refer to
// physical addresses starting at pa. va and size might not
// be page-aligned.
static int
mappages(pde_t *pgdir, void *va, uint size, uint pa, int perm)
{char *a, *last;pte_t *pte;a = (char*)PGROUNDDOWN((uint)va);last = (char*)PGROUNDDOWN(((uint)va) + size - 1);for(;;){if((pte = walkpgdir(pgdir, a, 1)) == 0)return -1;if(*pte & PTE_P)panic("remap");*pte = pa | perm | PTE_P;if(a == last)break;a += PGSIZE;pa += PGSIZE;}return 0;
}
……

参考文献

[1] xv6虚拟内存-博客园
[2] xv6 virtual memory-hexo
[3] xv6内存管理-简书
[4] xv6内存管理-CSDN

XV6源代码阅读-虚拟内存管理相关推荐

  1. XV6源代码阅读-中断与系统调用

    XV6源代码阅读-中断与系统调用 Exercise1 源代码阅读 1.启动部分: bootasm.S bootmain.c 和xv6初始化模块:main.c bootasm.S 由16位和32位汇编混 ...

  2. XV6源代码阅读-文件系统

    Exercise1 源代码阅读 文件系统部分 buf.h fcntl.h stat.h fs.h file.h ide.c bio.c log.c fs.c file.c sysfile.c exec ...

  3. XV6源代码阅读-进程线程

    文章目录 Exercise1 源代码阅读 Exercise2 带着问题阅读 参考文献 Exercise1 源代码阅读 基本头文件:types.h param.h memlayout.h defs.h ...

  4. 低层级GPU虚拟内存管理引论

    低层级GPU虚拟内存管理引论 Introducing Low-Level GPU Virtual Memory Management CUDA应用程序越来越需要尽可能快速高效地管理内存.在CUDA 1 ...

  5. 非常好!!!Linux源代码阅读——环境准备【转】

    Linux源代码阅读--环境准备 转自:http://home.ustc.edu.cn/~boj/courses/linux_kernel/0_prepare.html 目录 Linux 系统环境准备 ...

  6. Tomcat源代码阅读系列之八:Tomcat 设计模式总结

    本篇我们将来分析一下Tomcat中所涉及到设计模式,本文我们将主要来分析 外观模式 , 观察者模式 , 责任链模式 , 模板方法模式 , 命令模式 . 在开始本文之前,笔者先说明一下对于设计模式的一点 ...

  7. Linux 源代码阅读知识点及要求

    说明:1.本次源代码阅读,以Linux 最新的稳定版本(2.6)为主: 2.源代码下载地址: 在官方站点 www.kernel.org 上最新稳定版本是 2.6.13.2: 在清华的 ftp 上随时都 ...

  8. Linux虚拟内存管理 | 虚拟地址与物理地址映射、段错误SIGSEGV

    目录 x86 内存寻址 x86 分页机制 虚拟内存地址管理 虚拟地址与物理地址映射 - do_page_fault() 推荐阅读 Linux的内存管理分为 虚拟内存管理 和 物理内存管理,本文主要介绍 ...

  9. 【转】Tomcat总体结构(Tomcat源代码阅读系列之二)

    本文是Tomcat源代码阅读系列的第二篇文章,我们在本系列的第一篇文章:在IntelliJ IDEA 和 Eclipse运行tomcat 7源代码一文中介绍了如何在intelliJ IDEA 和 Ec ...

最新文章

  1. OpenNESS 的 5GC 融合实践
  2. 自己实现内存操作函数memset(),memcmp(),memcpy(),memmove()
  3. Java数据持久层框架 MyBatis之背景知识一
  4. GDCM:gdcm::XMLPrinter的测试程序
  5. Jacoco字节码植入原理(源码分析)
  6. Dynamics CRM On-Premise V9安装手记
  7. ReSIProcate环境搭建
  8. c++用一级运算比较大小_孩子数学运算难?小学数学速算技巧顺口溜都在这里了!...
  9. springboot做网站_SpringBoot项目实战(3):整合Freemark模板
  10. 新职业风口已至!人社部宣布这 10 个职业缺口近千万!
  11. DataGrid小扩展
  12. Oracle【IT实验室】数据库备份与恢复之三:OS备份/用户管理的备份与恢复
  13. 杭电OJ刷题指南(ACM)
  14. 对计算机网络的认识论文800,对计算机的认识论文
  15. 网站域名综合查询-批量免费网站域名综合查询工具
  16. CSP 201809-1 卖菜
  17. 再读《终身成长》——重塑思维
  18. 时尚html输入框,12款经典时尚的HTML5应用
  19. 路由宝刷华硕rt-n14u_如何在2019年取消硬砖路由器的砖块化(以华硕RT-N16为例)
  20. onclick绑定点击事件不触发

热门文章

  1. 使用 Nginx 部署前后端分离项目,解决跨域问题
  2. C++模板 —— 万字带你了解C++模板(蓝桥杯算法比赛必备知识STL基础)
  3. ROS系统学习5---OpenCV的使用
  4. 总结:VC小知识!(网上找的)
  5. cdc有哪些rapper_CDC说唱会馆在圈内是一个什么样的存在
  6. html中怎样隐藏列,关于jquery:隐藏/显示HTML表中的列
  7. 表格比手机屏幕宽时不压缩,可左右滚动,格子内容不换行
  8. h5 移动开发 html页面跳转,iosh5混合开发项目仿app页面跳转优化
  9. 【蓝桥杯题目分析】2014年第五届——第二题:切面条
  10. 读书笔记(VII) 人生五大问题