Jos - lab4 (Part A) Multiprocessor support

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

 613         static uintptr_t base = MMIOBASE;
 633
 634         pa = ROUNDDOWN(pa, PGSIZE);
 635         size = ROUNDUP(pa + size, PGSIZE) - pa;
 636         boot_map_region(kern_pgdir, base, size, pa, PTE_PCD|PTE_PWT|PTE_W);
 637         base += size;
 638         if(base >= MMIOLIM)
 639                 panic("mmio_map_region not implemented");
 640         return (void *)(base-size);
 

Exercise 2. Read boot_aps() and mp_main() in kern/init.c, and the assembly code in kern/mpentry.S. Make sure you understand the control flow transfer during the bootstrap of APs. Then modify your implementation of page_init() in kern/pmap.c to avoid adding the page at MPENTRY_PADDR to the free list, so that we can safely copy and run AP bootstrap code at that physical address. Your code should pass the updated check_page_free_list() test (but might fail the updated check_kern_pgdir() test, which we will fix soon).

 328         int i;
 329         int lower_pgnum = PGNUM(IOPHYSMEM);
 330         int upper_pgnum = PGNUM(ROUNDUP((int)boot_alloc(0) - KERNBASE,PGSIZE)     );
 331         int mpentry_pgnum = PGNUM(MPENTRY_PADDR);
 332         page_free_list = NULL;
 333         for (i = 0; i < npages; i++) {
 334                 if ((i == 0) || ((i >= lower_pgnum) && (i < upper_pgnum)) ||      (i == mpentry_pgnum)) {
 335                         pages[i].pp_ref = 1;
 336                         pages[i].pp_link = NULL;
 337                         continue;
 338                 }
 339                 pages[i].pp_ref = 0;
 340                 pages[i].pp_link = page_free_list;
 341                 page_free_list = &pages[i];

Question

  1. Compare kern/mpentry.S side by side with boot/boot.S. Bearing in mind that kern/mpentry.S is compiled and linked to run above KERNBASE just like everything else in the kernel, what is the purpose of macro MPBOOTPHYS? Why is it necessary in kern/mpentry.S but not in boot/boot.S? In other words, what could go wrong if it were omitted in kern/mpentry.S?
    Hint: recall the differences between the link address and the load address that we have discussed in Lab 1.
A: It calculate the exact code address in memory. Without MPBOOTPHYS, all the address will be in userspace of virtual memory now, because the code is already running under protect mode.

Exercise 3. Modify mem_init_mp() (in kern/pmap.c) to map per-CPU stacks starting at KSTACKTOP, as shown in inc/memlayout.h. The size of each stack is KSTKSIZE bytes plus KSTKGAP bytes of unmapped guard pages. Your code should pass the new check in check_kern_pgdir().

 302         int kstacktop_i;
 303         int i;
 304         for (i = 0; i < NCPU; i++) {
 305                 kstacktop_i = KSTACKTOP - i * (KSTKSIZE + KSTKGAP);
 306                 boot_map_region(kern_pgdir, (uintptr_t)(kstacktop_i - KSTKSIZE), KSTKSI     ZE, PADDR(percpu_kstacks[i]), PTE_W|PTE_P);
 307         }

Exercise 4. The code in trap_init_percpu() (kern/trap.c) initializes the TSS and TSS descriptor for the BSP. It worked in Lab 3, but is incorrect when running on other CPUs. Change the code so that it can work on all CPUs. (Note: your new code should not use the global ts variable any more.)

144         int cpu_i = thiscpu->cpu_id;
145         struct Taskstate ts;
146         // Setup a TSS so that we get the right stack
147         // when we trap to the kernel.
148         thiscpu->cpu_ts.ts_esp0 = KSTACKTOP - cpu_i * (KSTKSIZE + KSTKGAP);
149         thiscpu->cpu_ts.ts_ss0 = GD_KD;
150
151         // Initialize the TSS slot of the gdt.
152         gdt[(GD_TSS0 >> 3) + cpu_i] = SEG16(STS_T32A, (uint32_t) (&thiscpu->cpu_ts),
153                                                 sizeof(struct Taskstate), 0);
154         gdt[(GD_TSS0 >> 3) + cpu_i].sd_s = 0;
155
156         // Load the TSS selector (like other segment selectors, the
157         // bottom three bits are special; we leave them 0)
158         ltr(GD_TSS0 + ((cpu_i << 3) & (~0x7)));
159
160         // Load the IDT
161         lidt(&idt_pd);

Exercise 5. Apply the big kernel lock as described above, by calling lock_kernel() and unlock_kernel() at the proper locations.

Too easy to put the code here, notice that these are the entrance and exit  of kernel.

Question

  1. It seems that using the big kernel lock guarantees that only one CPU can run the kernel code at a time. Why do we still need separate kernel stacks for each CPU? Describe a scenario in which using a shared kernel stack will go wrong, even with the protection of the big kernel lock.
A: Think about below scenario: If we are in interrupt handling, it will use the kernel stack automatically before we get the lock, then the stack will be contaminated.


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值