Me, Operating Systems, Technology, Sun Microsystems and Stuff!

Paging support for MouthOS

This week I’ve been on the Solaris Internals course at work and I’ve already learnt an awful lot about how Solaris deals with processes (including threads and light weight processes), system calls, scheduling, memory management (hardware and software), paging and swapping! All of this and it’s only 3 days in.

However, one of the things about this is I’ve very quickly realised how far I’ve still got to go with MouthOS and how much I’ve still got to learn. A great example of this is in regards to memory management… Intel, it would appear, offer two different methods of dealing with memory - segmentation and paging. It was my impression that you could basically choose which you wanted to use when writing your OS and so I decided to use segmentation for MouthOS initially.

Unfortunately the Solaris Internals course has given me a bit of a rude awaking - I’ve realised that in order to use Paging you must first enable Segmentation. However, there are many different ways you can section off your RAM before you even get to paging….

Flat Model (which is what I’m going to be changing to) is where you basically say all of the address space (i.e. 32Bit address space is 4GBytes, even if you system only has 2GBytes) can be used for anything with no restrictions on who can do what - i.e. there is no hardware translation of memory accesses in regards to segments. When I say ‘no translation’ that’s not strictly true… because you still have to specific a segment in the GDT the processor will basically prefix every memory address with 0, so the effect is that there is no ‘translation’ but at the same time there is!

There is obviously a problem with this - if I have a process running, and paging isn’t enabled, and I try and access more than 2GBytes of memory from my process it won’t actually physically exist. However, because there are no checks - no exceptions will be raised and your system is likely to fall over pretty quickly. If you’ve got paging going on then there is no problem, a page fault will be generated and the kernel can load in the appropriate page somewhere else.

Protected Flat Model (which is what Solaris, Linux etc use) is where you limit the segment size to the size of the Physical Memory. In other words, instead of providing your processes with the fully available address space, you provide them with an address space that matches the amount of physical RAM. As such, if anything tries to access a memory address greater than the physically available memory a general protection exception will fire and the kernel will be able to deal with it.

Generally when using the Protected Flat Model you would have 4 sections. 2 of these sections will be in Ring 0 and two will be in Ring 3. Ring 0 is the Kernel ring and the two sections will define the text and data sections. It will start at memory location 0 and proceed to the maximum memory location available in physical memory. I.e. 0 -> 2MBytes. The LDT in Ring 3 (user space) will start at 0 + size of kernel and will end at the maximum memory location available in memory.

For example, assuming the Kernel is 2MBytes and the available RAM is 2GBytes, the LDTs would be along the following lines:

Section            Ring		Protection            Base            Offset
TEXT                0  		r-x                   0               2GBytes
DATA                0           rwx                   0               2GBytes
TEXT                3           r-x                   2MBytes         2GBytes
DATA                3           rwx                   2MBytes         2GBytes

This prevents anything which runs in Ring 3 from ever touching the first 2MBytes of memory where the Kernel is stored, however, the Kernel running in Ring 0 can access its own structures and text, and that of Ring 3 also.

Multi-Segment Model basically uses a similar principle to the protected flat model except it adds yet more sections, this time as many as you could care to imagine - each one defining text, data, bss, stacks, heap sections which are available for individual processes and even thread within a process.

Once you’ve sorted out your segmentation, reading my ‘Intel 64 and IA-32 Architectures Software Developer’s Manual’, enabling paging seems to be relatively simple. From what I can tell I need to setup a page directory, pass the memory location of this page directory to cr3 (control register 3 - which actually acts as a context register) and then set bit31 of cr0 (control register 0) to 1… dah da! Oh, and then of course I’ll have to sort out all the other entertaining things such as a page_fault() handler for when we get a request for a page that isn’t currently in memory - however, for the moment I think I’ve got quite enough to be getting on with.

So far my beautiful “proc_enable_paging” assembly routine is looking a little bare….

  proc_enable_paging:
                mov eax, cr0
                and eax, 0x80000000 ; Set bit 31 (PE) = 1.
                mov cr0, eax
                ret

Leave a Reply