[NSWI004] MIPS specifics wrt virtual memory

Petr Tůma petr.tuma at d3s.mff.cuni.cz
Sun Dec 29 12:38:56 CET 2019


Hi,

> AFAIK so far we have been working in virtual addresses corresponding
> to kseg0 i.e. range 0x8000_0000 - 0xA000_0000. The initial TBL
> configuration is therefore, I presume, filled with 32 pages which
> corresponds to memory limits set for tests.

Actually, that's not entirely accurate. With MIPS, the mapping for the range of addresses in kseg0 is hardwired - that is, when software uses an address between 0x80000000 and 0x9FFFFFFF, TLB is not even used and the address is translated to a physical address from 0x0 to 0x1FFFFFFF by a built in translation mechanism that the software cannot influence.

> The assignment says that we shall implement page allocator inside
> 512MB in kseg0 and on the top of that implement a heap allocator which
> is just a modified version of our previous allocator. In addition to
> that we shall implement a separate structure for mapping virtual
> address spaces of each thread to some physical addresses in kseg0.

Yes. Or, again, for sake of accuracy - you're not mapping virtual address spaces to "physical addresses in kseg0", you're mapping virtual address spaces to physical addresses in the 0x0 to 0x1FFFFFFF range that the addresses in kseg0 also happen to map to.

> Therefore our page allocator would have some internal static data
> structure which would store status of pages in kseg0 and page_alloc
> would return physical address (i.e. virtual address from kseg0) of
> allocated pages. On the top of that a heap allocator would allocate
> pages from page allocator and work in that space i.e. kseg0. However
> now that I add different address spaces to this i.e. new address space
> for each process and even kernel one how can I make kernel heap
> allocator work, since modifications to TLB would break access to it
> form other threads not sharing the same AS.

You do not have to worry about TLB content in kseg0. When a thread executes in the kernel and accesses memory through kseg0 addresses, TLB is not involved. Only when a thread transitions to userspace and accesses useg addresses, TLB is used.

Also remember that when executing in userspace, threads cannot access memory through kseg0 addresses - that is only possible when executing in the kernel. So it all kind of fits in - when userspace code needs something from the kernel, it will execute a syscall, thus start executing in the kernel, and the kernel data structures will be available. So every time your threads access kernel heap, they do it from kernel mode, using the same hardwired mapping of kseg0 addresses.

You can, of course, make the physical pages that contain the kernel heap also accessible through useg addresses, by filling the TLB entries as necessary. However, there is probably no reason to do that - code executing in userspace is by definition not trusted, and you do not really want to give it access to kernel data. Plus, userspace would necessarily have to use virtual addresses from the useg range, which means that whatever kseg0 addresses the kernel would write to its heap, the userspace code would have to convert - in one word, a mess :-)

> I thought that in general paging should have access to physical memory
> i.e. know how big memory is and what pages are allocated to which
> process in its page table. Then a page allocator would return a
> virtual address for a page for a given process which made the request
> and a heap allocator can work on top of that in terms of virtual
> addresses and I'm not sure how a kernel allocator should work in this
> context.

The idea of the design we suggest in our assignment is as follows: you will have a physical page allocator, which accesses all memory through kseg0 addresses. That makes the allocator kind of simple - it does not have to care about virtual address mappings, and it does not have to care about threads and associated address spaces. It simply tracks what pages are used and what are free.

The virtual address space support only comes on top of this allocator. When you create a thread with a new address space, some internal address space structure would be used to track what physical pages that address space has obtained from the physical page allocator and what virtual addresses they map to. That address space structure would also be consulted during the TLB fault handling.

With this design, it makes sense for the page allocator to return physical addresses, or their kseg0 counterparts, because it does not know anything about virtual memory.

Naturally, other designs are also possible, but they would likely end up being more complex.

> Next I'm not sure how is TLB exception handled, does it go to function
> handle_general_exception with some special code (I found that codes
> 1-3 are reserved for this) and then we call tlb_refill or is it
> somehow "hardwired" (in terms of address space) to where this handler
> code shall be and we don't need to care about it in
> handle_general_exception?

Actually, it's both :-) there is a specialized TLB Refill exception vector, which gets called in most cases. We have prepared an assembly handler for that in handlers.S, which calls a handle_tlb_refill () C function. However, when the processor is already handling another exception and the EXL bit of the Status CP0 register is set, the TLB Refill exception is instead delivered through the general exception handler. Plus, there is the TLB Invalid exception, which is also delivered through the general exception handler.

Hope this helps, Petr


More information about the NSWI004 mailing list