Ensuring task protection using segmentation

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
limp
Member
Member
Posts: 90
Joined: Fri Jun 12, 2009 7:18 am

Ensuring task protection using segmentation

Post by limp »

Hi all,

I would like to use segmentation for allocating a fixed memory junk of a predefined contiguous memory region to each of my OS tasks.

For example, let's say that I use the 0x100000 - 0x120000 memory region. This region is of 128 KB so if I keep 64 KB for the kernel code, stack and data, and allocate 2KB to each task of the rest 64 KB, I will have 32+1 segments.

Image

My understating says that apart from creating 33 GDT descriptors for the code and 33 for the data of each segment, I will need to define these segments in my linker script as well. Is that right?

First question: How am I mapping the data and code of a task into its segment?

E.g. Let's say that I want to have the code and data of Task A into its 2 KB segment. How can I achieve this? Should I use something like the keyword __attribute__ along with section attribute in GCC?

Second question: How am I restricting a task to change data only in its segment?

E.g. Task A should be able to affect only the data in its 2 KB segment and nothing else.

NOTE: I am aware of the paging alternative but I would like to use segmentation instead of paging.

Any help will be much appreciated.

Thanks in advance.
limp
Member
Member
Posts: 90
Joined: Fri Jun 12, 2009 7:18 am

Re: Ensuring task protection using segmentation

Post by limp »

Thanks very much for the help guys!

I think I've made some progress but still have to make some more steps in order to get it work.

I have a couple more things for which I am not quite sure about:

1) In my scheduler, when I am about to execute a task I trying to switch to the task's segment and jump to the task's entry point. For doing that, I am saving the currently used segments (by pushing them into the stack), I am loading the GDT entry of the task (lgdt) and then I am using a call to jump to it (e.g. call TaskA). After the call, I am restoring the segment registers (pop). Does this sound like a good way of doing it? The "lgdt" instruction sets also the segment registers according to the loaded GDT entry or this is something I should do? Note that I don't want to restore the context of the task but start executing it again (I only have periodic co-operative tasks), so it should be quite straightforward.

2) I am trying to link the kernel into its own segment and not link the tasks in there. Could you please suggest a way of doing that? I think I've managed to link the tasks into their segments but they are also linked in the kernel segment, i.e. I need somehow to exclude the tasks from the kernel segment.

Thanks a lot for the useful help, it's really appreciated.
rdos
Member
Member
Posts: 3310
Joined: Wed Oct 01, 2008 1:55 pm

Re: Ensuring task protection using segmentation

Post by rdos »

A couple of issues. To just define fixed segments somehow defeats the purpose of segmentation. You should allocate the precise amount of memory needed for each task segment on demand, and map it to a selector with the exact limit. This will stop tasks from accessing code or data outside of their segments.

Second, it is generally a bad idea to reload GDT. It can work if some basic segments are always mapped to the same addresses (most importantly the code that changes GDT). This is similar to changing CR3 register for paging. Some things needs to be mapped in the same way everywhere.

Third, your kernel will always need to access data outside of it's own code & data segment, and then it needs these to be far pointers (often 16:32 pointers).
limp
Member
Member
Posts: 90
Joined: Fri Jun 12, 2009 7:18 am

Re: Ensuring task protection using segmentation

Post by limp »

Thank you all,
berkus wrote:
limp wrote:2) I am trying to link the kernel into its own segment and not link the tasks in there. Could you please suggest a way of doing that? I think I've managed to link the tasks into their segments but they are also linked in the kernel segment, i.e. I need somehow to exclude the tasks from the kernel segment.
Kernel usually needs access everywhere, so you can create ring0 descriptors with base 0 and size 4Gb for kernel, of course it will include tasks into kernel segment, but this is most probably what you want.
I wasn't talking about the kernel GDT descriptors but about the kernel code in memory, sorry if it wasn't clear enough.
That is, the linker script that I am currently using maps the whole kernel including the tasks starting from 0x00100000. What I would like to do is to define a kernel segment in the linker script which will have a predefined size of 64 KB for example and it will include the whole kernel code apart form the tasks (which will be mapped on their own segment).
in task1:
code executes from CS:entrypoint, data is available via DS (and ES on x86), FS/GS can be used to access global/kernel memory for example.
Can you please tell me a bit more on how to use the FS/GS segments for accessing global/kernel memory from within a task segment. Eventually, what I want to do is the tasks to be able to call the kernel routines which are in the kernel segmebt but not being able to modify anything outside their segment.

Thanks again.
Post Reply