Hi,
Avidanborisov wrote:But then it hit me - why should the virtual allocator be responsible for finding free pages with it's own 4MiB bitmap, when the paging structures (PD's and PT's) already store this information?
Avidanborisov wrote:What's a good way to design the relationship between the physical allocator, the virtual allocator, the paging implementation and the kernel heap?
Assume your VMM supports 3 different area types:
- memory mapped file
- usable RAM
- unusable
Now assume for each area type there can be multiple "page states":
- present memory mapped file
- not present memory mapped file
- present usable RAM
- not present usable RAM (allocate on write)
- not present usable RAM (data was sent to swap space)
- unusable
If I have a 33 MiB file that's mapped at virtual address 0x12345000 and I've finished using that file and don't need the memory mapping any more, but do need more usable RAM; I ask the virtual memory manager to convert 33 MiB at 0x12345000 to the "usable RAM" area type. Imagine a function like this:
Code: Select all
VMM_convertPageAreaTypeToUsableRAM(void *virtualAddress, int count) {
while(count > 0) {
switch( getCurrentPageState(virtualAddress) ) {
case PRESENT_MMAP:
// Just change "available" bits in page table entry used to store page state to "PRESENT_RAM"
break;
case NOT_PRESENT_MMAP:
// Just change "available" bits in page table entry used to store page state to "NOT_PRESENT_RAM_ALLOC_ON_WRITE"
break;
case PRESENT_RAM:
case NOT_PRESENT_RAM_ALLOC_ON_WRITE:
case NOT_PRESENT_RAM_ON_SWAP:
// It must already be the area type we want
break;
case UNUSABLE:
// Just change "available" bits in page table entry used to store page state to "NOT_PRESENT_RAM_ALLOC_ON_WRITE"
break;
default:
kernel_panic("Unsupported page state detected in VMM(!)");
break;
}
count--;
virtualAddress += 4096;
}
In this case the VMM never allocates or frees any physical RAM at all.
Then (later); I ask the virtual memory manager to convert 512 MiB at 0x12300000 to the "unusable" type. Imagine a function like this:
Code: Select all
VMM_convertPageAreaTypeToUnusable(void *virtualAddress, int count) {
while(count > 0) {
switch( getCurrentPageState(virtualAddress) ) {
case PRESENT_MMAP:
case PRESENT_RAM:
// Free physical page and change "available" bits in page table entry used to store page state to "UNUSABLE"
break;
case NOT_PRESENT_MMAP:
case NOT_PRESENT_RAM_ALLOC_ON_WRITE:
// Just change "available" bits in page table entry used to store page state to "UNUSABLE"
break;
case NOT_PRESENT_RAM_ON_SWAP:
// Tell whatever handles swap space to free the disk space it was using for this page
// Change "available" bits in page table entry used to store page state to "UNUSABLE"
break;
case UNUSABLE:
// It must already be the area type we want
break;
default:
kernel_panic("Unsupported page state detected in VMM(!)");
break;
}
count--;
virtualAddress += 4096;
}
Of course this is "very over-simplified" to make it easier to understand the general idea. In practice you might have more area types (memory mapped IO, shared memory, thread specific storage, "never send to swap" variants, etc) and more page states; plus things like page/cache colouring and NUMA optimisations to improve performance.
Now assume that some processes are using a general purpose heap like malloc() or new(); some use their own custom designed things (e.g. dedicated pools for different object types); some use no memory management at all (e.g. everything allocated at compile time with static arrays); some use a mixture of 2 or more completely different techniques, etc.
It would be wrong/bad for kernel to force its own assumptions onto processes and prevent processes from doing their own thing.
This means that kernel's VMM should not allocate virtual space on behalf of processes, and should only provide "convert area of size X at starting at virtual address Y to area type Z" functionality that the process can use however it likes to implement whatever heap (or lack of heap) it feels like.
For the kernel itself, nothing really changes. The kernel's heap (if it uses one) decides which areas of kernel space it wants to use how; and the kernel's VMM still only provides the same "convert area of size X at starting at virtual address Y to area type Z" functionality. As far as the VMM is concerned the only real difference is the security checks (kernel is allowed to change things in kernel space while processes aren't).
Also note that there's no sane reason why the kernel itself can't (with a little care) use features that the VMM supports that reduce physical RAM consumption and/or improve performance. For example; my micro-kernels tend to use "allocate on write" a lot; and (in conjunction with "compressed RAM as swap space" feature I'm planning) would benefit from being able to send message queues to swap space.
Cheers,
Brendan