Virtual Addressing...

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.
Lprogster
Member
Member
Posts: 174
Joined: Tue Nov 14, 2006 11:59 am

Virtual Addressing...

Post by Lprogster »

...

Thank you guys,
Lster
Last edited by Lprogster on Tue Oct 23, 2007 11:07 am, edited 2 times in total.
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Re: Virtual Addressing...

Post by jnc100 »

Lprogster wrote:Am I right in thinking this is slower?
Not exactly. There is an overhead associated with switching virtual address spaces. You'll have to balance that against the overhead associated with position-independent code.

The main benefit of using a separate address space for each process is that you are protecting each process from each other, so that an application cannot accidentally or maliciously read/write another process' address space. In addition, you can protect the kernel from the processes.

There are additional benefits such as allowing certain processes access to memory-mapped devices and not others, implementing copy-on-write etc.

For more information, might I suggest you start with Memory Management and Context Switching

Regards,
John.
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Post by JAAman »

Am I right in thinking this is slower?
depends on how its done... and which CPU mode your in

but as John said, the most important reason to do this, is for protection from errant or malicious programs

So anyway... I want to add paging I suppose. I'm not sure on how to add virtual addressing... From what I've read, I need to do something like this:
1. Allocate a page table per process.
there are different ways, but the generally accepted convention is for each task to have a page table, and the kernel to be mapped into the top part of each one (the top pages can be reused, without changing) -- if you use the global bit, and dont change the mapping of the kernel pages, then you can eliminate some of the overhead of context switching
2. Alter the GDT for different segments.
there isnt anything you need to do with your GDT specifically for separate address spaces

you need to do 2 things here
1) make sure that your user code is in ring3 while your kernel code is in ring0 (which you should already do) -- you can have much more complex systems, but most of the time you only have 1 code and 1 data segment used for all user tasks, and 1 code/1 data segment used for kernel
2) add a segment for your TSS (again, you should already be doing this) -- if you use hardware task-switching you must have the correct CR3 entry in the TSS, if you use software task-switching, you dont need to worry about the CR3 entry at all)
3. Every task switch I disabled the current page table and enable the next tasks one.
you dont really disable the current page table, you just change CR3 to point to the new page table -- changing the contents of this register is all that is necessary to change address spaces



it should be quite easy to set up, just remember to map your kernel globally into all address spaces or (as someones signature used to say) bad things happen when you swap out your page swapping code
Lprogster
Member
Member
Posts: 174
Joined: Tue Nov 14, 2006 11:59 am

Post by Lprogster »

...

Thank you again guys,
Lster
Last edited by Lprogster on Tue Oct 23, 2007 11:07 am, edited 1 time in total.
jnc100
Member
Member
Posts: 775
Joined: Mon Apr 09, 2007 12:10 pm
Location: London, UK
Contact:

Post by jnc100 »

A bit of clarification:

A virtual address space, in 32-bit pmode, is defined by a 4kiB long page directory which then contains either the physical addresses of 4kiB sized page tables and/or the physical addresses of 4MiB sized pages.

You can disable a page table by clearing its present bit, but JAAman was referring to changing the physical address of the page directory for the current address space, which exists in CR3.


A typical setup would be:

- A physical memory manager (pmm) which hands out, on command, the physical addresses of free 4kiB sized and 4kiB aligned pages.
- A 4kiB page directory for each process, obtained from the pmm
- One 4kiB page table, for the kernel. Note that a page table contains 1024 entries which reference individual 4kiB pages of physical memory. Therefore, each page table as a whole represents 4MiB of memory.
- You map the kernel page table to the same place in each process.
- One (or maybe more) 4kiB page tables per process which represent the code and data of the actual process. You map different ones into each address space.
- On a task switch, you merely switch cr3 and all the registers to those of the new process.

Virtual memory management is a term by which different people mean different things. Some use it to mean the mapping of physical to virtual addresses, others mean the dividing up and handing out of small bits of the virtual address space ala malloc.

The actual entries you need to put in the page tables are described in the Intel docs.

Regards,
John.
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Post by JAAman »

You can disable a page table by clearing its present bit, but JAAman was referring to changing the physical address of the page directory for the current address space, which exists in CR3.
ya, sorry about that

i assumed since he said he already had paging enabled and was asking about task-switching, that he was referring to the page directory, but i shouldnt have copied his use of terms

I suppose segments are used for segmentation...? (Well duh!)
yes... and you can still use them completely if you want but most people dont (its much more complicated to do so)

under most OSs, there are only a few entries in the GDT used: 1 code/1 data for ring 3 (user code), 1 code/1 data for ring0 (kernel), 1 for TSS (1 per CPU), sometimes 1 for VMode if you use it

so segments are used primarily for protection
Can't I just XOR the current page table by 3 (011b) to disable it? And enable it with OR 3...?
well, all you need is XOR 1 and OR 1, not 3 -- the R/W bit is ignored (as are all other bits) when P=0 (reference 3A:3.7.7)

yes you can do this, but for task-switching it is unnecessary -- normally the only time the present bit is cleared, is when you swap the page to disk
Lastly... How do I map physical and virtual memory with paging? I realise this is quite broad...
quite broad indeed...
John gave about as good an explaination as can be given to such a broad question...

i suggest taking another look at intel manuals, volume 3A, sections 3.6, 3.7, & 3.12
Lprogster
Member
Member
Posts: 174
Joined: Tue Nov 14, 2006 11:59 am

Post by Lprogster »

...
Last edited by Lprogster on Tue Oct 23, 2007 11:07 am, edited 1 time in total.
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Post by JAAman »

basically, you cannot jump directly to a higher privilege level (so your apps cannot call kernel level code), therefore, to return to a higher level (lower numbered ring) you must use a gate of some kind -- normally a soft interrupt (using the int instruction)

there are other ways, but soft-ints are the easiest to setup and use, to transfer control to the kernel (for making syscalls for example)

for returning control to ring3, you generally use a iret -- for starting the task for the first time, simply place the appropriate values onto the stack as if it just received an inter-ring int, then iret to the entry point in the ring3 code
Lprogster
Member
Member
Posts: 174
Joined: Tue Nov 14, 2006 11:59 am

Post by Lprogster »

Thank you,
Lster
Last edited by Lprogster on Tue Oct 23, 2007 11:08 am, edited 3 times in total.
Lprogster
Member
Member
Posts: 174
Joined: Tue Nov 14, 2006 11:59 am

Post by Lprogster »

(Original post updated - I hope I cleared up a few things. Just ask for any more information...)
User avatar
JAAman
Member
Member
Posts: 879
Joined: Wed Oct 27, 2004 11:00 pm
Location: WA

Post by JAAman »

Can you tell me, am I correct in thinking that I can change the security ring level by changing the segment registers?
yes and no...
The next thing I'm wondering is how to stop it running code like:

Code: Select all

cli

mov ax, 0x10
mov es, ax

hlt
bits 0 & 1, for segment registers other than CS, is the RPL, which can only be used to downgrade, but not upgrade, your privilege level

in this case, your program is loading 0X10 into ES, 0X10 has a RPL of 0, but, if your CPL is 3, then it ignores the RPL of 0:
intel 3A:4.5 wrote: ... The processor checks the RPL along with the CPL to determine if access to a segment is allowed. Even if the program or task requesting access to a segment has sufficient privilege to access the segment, access is denied if the RPL is not of sufficient privilege level. That is, if the RPL of a segment selector is numerically greater that the CPL, the RPL overrides the CPL, and vice versa...
therefore, when loading a segment selector into a data selector, the CPU checks if DPL > RPL and DPL > CPL, if either of these checks fail, then a GPF is triggered, and the segment selector is not loaded (intel 3A:4.6)

your code segment selector determines which ring you are currently in, you cannot jump to a higher or lower privilege level, this prevents lower level code from trying to 'upgrade' its privileges, therefore, a higher ring will never be able to access a lower ring data segment, since it cannot change its CPL (which would require a jump to higher privilege code, which is not allowed) -- see intel 3A:4.8 for more detail on privilege level changes for code segments
Lprogster
Member
Member
Posts: 174
Joined: Tue Nov 14, 2006 11:59 am

Post by Lprogster »

Thank you for your reply.

...

So why does that GPF? How can I get it all working?

Thank you yet again,
Lster
Last edited by Lprogster on Fri Jun 15, 2007 2:45 am, edited 1 time in total.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

what occurs to me is that you keep one variable for the kernel level stack while it normally needs two - the esp0 field in the TSS != the esp that should be provided when the task_switch() function returns.

For the rest, use bochs' debugger to see where the code breaks (bad stack format?)

also, the cli opcode is not necessary - There's a flag in the IDT for that (trap gate vs interrupt gate)
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Lprogster
Member
Member
Posts: 174
Joined: Tue Nov 14, 2006 11:59 am

Post by Lprogster »

...
Last edited by Lprogster on Tue Oct 23, 2007 11:09 am, edited 2 times in total.
User avatar
Combuster
Member
Member
Posts: 9301
Joined: Wed Oct 18, 2006 3:45 am
Libera.chat IRC: [com]buster
Location: On the balcony, where I can actually keep 1½m distance
Contact:

Post by Combuster »

get a few floppy images with linux and grub and mount them into bochs :wink:
"Certainly avoid yourself. He is a newbie and might not realize it. You'll hate his code deeply a few years down the road." - Sortie
[ My OS ] [ VDisk/SFS ]
Post Reply