MIT 6.1810 Lab: page tables

Speed up system calls (easy)

任务

通过在内核空间和用户空间之间通过共享只读存储区域内的数据,加速特定的系统调用。在每个进程被创建时,将一个只读的页映射到 USYSCALL。在这一页的开始部分,存储一个 struct usyscall 结构体,将它初始化来存储当前的进程的 pid。

实现

  • kernel/proc.h 中的 struct proc 定义中添加:
struct usyscall *usyscall;   // 加速系统调用,指向共享的页的指针
  • kernel/proc.c 中的 proc_pagetable() 添加:
if (mappages(pagetable, USYSCALL, PGSIZE, (uint64)(p->usyscall), PTE_R))
{
	uvmunmap(pagetable, TRAMPOLINE, 1, 0);
	uvmunmap(pagetable, TRAPFRAME, 1, 0);
	uvmfree(pagetable, 0);
	return 0;
}
  • kernel/proc.c 中的 allocproc() 添加:
// 为 usyscall 分配一页
if ((p->usyscall = (struct usyscall *)kalloc()) == 0)
{
	freeproc(p);
	release(&p->lock);
	return 0;
}
p->usyscall->pid = p->pid;
  • kernel/proc.c 中的 free_pagetable() 添加:
uvmunmap(pagetable, USYSCALL, 1, 0);
  • kernel/proc.c 中的 freeproc() 添加:
if (p->usyscall)
	kfree((void *)p->usyscall);
p->usyscall = 0;

任务

编写一个函数,接收 pagetable_t 参数,按照特定格式打印出页表。在 kernel/exec.c 中 return argc 之前添加 if(p->pid==1) vmprint(p->pagetable),来打印出第一个进程的页表。

实现

  • kernel/vm.c 中添加:
void print_pagetable(pagetable_t pagetable, int depth)
{
	for (int i = 0; i < 512; i++)
	{
		pte_t pte = pagetable[i];
		if (pte & PTE_V)
		{
			uint64 addr = PTE2PA(pte);
			printf("..");
			for (int i = 1; i < depth; ++i)
				printf(" ..");
			printf("%d: pte %p pa %p\n", i, pte, addr);
			if (depth < 3)
				print_pagetable(addr, depth + 1);
		}
	}
}

void vmprint(pagetable_t pagetable)
{
	printf("page table %p\n", pagetable);
	print_pagetable(pagetable, 1);
}
  • kernel/defs.h 中添加定义:
void vmprint(pagetable_t);
  • kernel/exec.c 中 return argc; 前添加:
vmprint(pagetable);

Detect which pages have been accessed (hard)

任务

实现一个系统调用 pgaccess(),报告哪些 page 被访问过。系统调用接收三个参数:第一个要检查的 user page 的虚拟地址,要检查的 page 的数量,一个 user 地址,指向缓冲区用来将结果存入一个 bitmask。

实现

  • 对应的系统调用已经添加,还需要添加系统调用的具体实现。

  • 首先在 kernel/riscv.h 中添加 PTE_A 的定义。

#define PTE_A (1L << 6) // the access bit
  • kernel/sysproc 中的 sys_pgaccess() 中添加从用户空间获取参数并实现系统调用。
int
sys_pgaccess(void)
{
	uint64 buf;
	int num;
	uint64 maskaddr;
	struct proc *p = myproc();
	uint64 mask;

	argaddr(0, &buf);
	argint(1, &num);
	argaddr(2, &maskaddr);
	if (num > 64)
		return -1;
	mask = 0;
	for (uint64 i = 0; i < num; ++i)
	{
		pte_t *pte;
		pte = walk(p->pagetable, buf + i * PGSIZE, 0);
		// 如果 page 已经被分配且被访问过
		if (pte != 0 && ((*pte) & PTE_A))
		{
			mask = mask | (1L << i);
			// 将 PTE_A 位重新设置为 0
			*pte = (*pte) & ~PTE_A;
		}
	}	
	if (copyout(p->pagetable, maskaddr, (char *)&mask, sizeof(mask)) < 0)
		return -1;
	return 0;
}
posted @ 2023-01-03 13:20  雪中的茶  阅读(258)  评论(0编辑  收藏  举报