##Lab2

这个Lab主要是编写内核内存管理的代码:

  1. 初始化物理内存, 并实现物理页的alloc free.
  2. 建立页目录, 页表的两层结构并设置权限.
  3. 编写页基本操作的代码, 创建 / 查询 / 插入 / 删除.
  4. 按需求初始化各个段的内存, 分配 kernel / user 的权限.

接下来, 我们一点一点的说完成该Lab需要注意的一些地方.

###Part 1

Physical Page Management

The operating system must keep track of which parts of physical RAM are free and which are currently in use. JOS manages the PC’s physical memory with page granularity so that it can use the MMU to map and protect each piece of allocated memory.

You’ll now write the physical page allocator. It keeps track of which pages are free with a linked list of struct PageInfo objects, each corresponding to a physical page. You need to write the physical page allocator before you can write the rest of the virtual memory implementation, because your page table management code will need to allocate physical memory in which to store page tables.

很明显, 这是需要我们写一个物理内存的分配器, 鉴于当前是物理内存, 所以分配的逻辑非常简单.

维护一个单链表 page_free_list

  • 当分配页面的时候, 从链表中移除链表头作为新的页.
struct PageInfo *
page_alloc(int alloc_flags)
{
	// Fill this function in
	// SUNUS, 23, October, 2013
	struct PageInfo *pp = page_free_list;
	if (!pp)
		return NULL;
	page_free_list = page_free_list->pp_link;
	if (alloc_flags & ALLOC_ZERO)
		memset(page2kva(pp), '\0', PGSIZE);
	pp->pp_link = NULL;
	return pp;
}
  • 当移除页面的时候, 把移除的页面加入到 page_free_list中.
    • 只有页面的引用计数为0时, 才会调用page_free
void
page_free(struct PageInfo *pp)
{
	// Fill this function in
	// SUNUS, 23, October, 2013
	assert(pp->pp_ref == 0);
	pp->pp_link = page_free_list;
	page_free_list = pp;
}

###Part 2

这部分是本Lab的重点, 首先. 需要了解 Linear address , Virtual address , Physical address 目前, 可以认为在接下来开启了分页机制之后, Linear addressVirtual address 是一回事.

在Linux下, 每个进程都有自己独立的地址空间, 32bit的系统下位4GB. 所以, 每个地址的长度都是四字节, 也正好是一个指针的大小. 在了解了Linux的分页机制之后, 可以看到一个Virtual address其实是由如下3个部分组成:

// A linear address 'la' has a three-part structure as follows:
//
// +--------10------+-------10-------+---------12----------+
// | Page Directory |   Page Table   | Offset within Page  |
// |      Index     |      Index     |                     |
// +----------------+----------------+---------------------+
//  \--- PDX(la) --/ \--- PTX(la) --/ \---- PGOFF(la) ----/
//  \---------- PGNUM(la) ----------/

页目录(Page directory)其实是一个长度为1024的整形数组, 里面的每个元素是指向每一个页表(Page table)的指针. 每个页表也是个长度为1024的整形数组, 里边的元素则是物理地址的值.

然一个虚拟地址的高10位是该地址对应的页目录索引, 用于获取页目录中指向该地址的页表的地址. 通过10~20位, 能够得到该地址在页表项的索引, 然后就能够得到该地址对应的物理地址, 最后, 虚拟地址的低12位加上物理地址的基地址. 就完成了由虚拟地址到物理地址的转换.

当前, 我们需要做的就是建立一个这样的页表以及页目录. 并且能够实现由虚拟地址到物理地址的转换. 具体可以参考 github code: kern/pmap.c

###Part 3

Initializing the Kernel Address Space 已经差不多了, 接下来我们需要初始化内存空间. 这里需要注意的就是在对pgdir, pte进行赋值之后. 在以后的读取操作时, 需要把低位的标志位mask掉. 不然会读取到错误的地址(原地址|flags)

###Done Lab2就此结束, 本Lab2虽然说的毕竟少. 但是其实代码量还是挺大的. 特别是指针类型和uint32_t类型的互相转换使用, 务必非常小心.

Git: rebase is better than pull

why we should use rebase more often, 为什么要多使用rebase Continue reading

Mit 6828 lab1 ex12, Backtrace

Published on October 13, 2013

Mit 6828 lab1 ex8-11 Printf, Stack

Published on October 12, 2013