MIT S6.828 Lab4学习记录(一)

167 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天,点击查看活动详情

这两天开了一个新坑,在框架下自己逐步实现一个xv6操作系统

一方面又要学习前端又要搞操作系统真的能烧掉cpu ,下面是我学习过程中记录的一些内容,方便自己啥也不知道的时候来看看

多处理器支持和合作多任务处理

首先,我们会将JOS拓展到多处理器系统上运行,然后实现一些新的JOS内核系统调用,以允许用户环境创建新的额外环境。还会实现协作轮询机制调度,允许内核在当前环境下自愿放弃CPU资源(或退出)时从一个环境切换到另一个环境。最后我们将实现抢占式调度,它允许内核在经过一段时间后从环境中重新控制CPU,即使环境并没有协作。

多处理器支持

我们将使JOS支持“对称多处理”(SMP),这是一种多处理器模型,其中所有CPU都可以等效访问系统资源,如内存和I / O总线。虽然SMP中的所有CPU在功能上都是相同的,但在引导过程中它们可以分为两种类型:

引导处理器(BSP)负责初始化系统和引导操作系统;并且只有在操作系统启动并运行后,应用处理器 (AP) 才会由 BSP 激活。

哪个处理器是 BSP 由硬件和 BIOS 决定。到目前为止,所有现有的JOS代码都在BSP上运行。

在SMP系统中,每个CPU都有一个随附的本地APIC(LAPIC)单元。LAPIC单位负责在整个系统中提供中断,同时还为其连接的CPU提供了唯一标识符。在本实验中,我们利用了 LAPIC 装置的以下基本功能(在 kern/lapic.c 中):

  • 读取 LAPIC 标识符 (APIC ID) 以告知我们的代码当前正在哪个 CPU 上运行(请参阅cpunum())。
  • 将处理器间中断 (IPI) 从 BSP 发送到 AP 以启动其他 CPU(请参见lapic_startap())。
  • 在 C 部分中,我们对 LAPIC 的内置计时器进行编程,以触发时钟中断以支持抢占式多任务处理(请参阅apic_init())。

处理器使用内存映射 I/O (MMIO) 访问其 LAPIC。在MMIO中,一部分物理内存硬连接到某些I/O设备的寄存器,因此通常用于访问存储器的相同加载/存储指令可用于访问设备寄存器。您已经在物理地址0xA0000看到了一个 IO 孔(我们用它来写入 VGA 显示缓冲区)。LAPIC位于一个从物理地址0xFE000000(32MB短于4GB)开始的洞中,因为地址太高了,我们无法在KERNBASE使用我们通常的直接映射进行访问。JOS 虚拟内存映射在 MMIOBASE 上留下了 4MB 的间隙,因此我们有一个地方来映射这样的设备。由于后面的实验会引入更多 MMIO 区域,因此你将编写一个简单的函数来分配该区域的空间,并将设备内存映射到该区域。

Exercise 1. Implement in kern/pmap.c. To see how this is used, look at the beginning of in kern/lapic.c. You’ll have to do the next exercise, too, before the tests for will run. mmio_map_regionlapic_initmmio_map_region

void *
mmio_map_region(physaddr_t pa, size_t size)
{
	static uintptr_t base = MMIOBASE;
    
	// Hint: The staff solution uses boot_map_region.
	size_t start = ROUNDDOWN(pa, PGSIZE);
	size_t end = ROUNDUP(size + pa, PGSIZE);
	if (base + end - start >= MMIOLIM) {
		panic("mmio_map_region: overflow MMIOLIM!\n");
	}

	size = end - start;
	boot_map_region(kern_pgdir, base, size, start, PTE_PCD | PTE_PWT | PTE_W);
	base += size;
	return (void *) (base - size);
}

观察我们之前的内存分配图,可以知道这里的base指向下一个区域的起始位置,这个位置就是MMIO区域的起始地址。剩下的代码和我们之前进行内存映射非常相似,通过取整页面大小来保证我们的MMIO从物理地址的[pa,pa+size)映射到[base,base+size)。在进行处理时我们要避免溢出MMIOLIM。最后根据Hint,使用boot_map_region()函数建立映射(注意,禁用缓存和写入)。最后更新base地址并且返回本次映射的起始位置。

等待更新......