Virtual Addressing...
Virtual Addressing...
...
Thank you guys,
Lster
Thank you guys,
Lster
Last edited by Lprogster on Tue Oct 23, 2007 11:07 am, edited 2 times in total.
Re: Virtual Addressing...
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.Lprogster wrote:Am I right in thinking this is slower?
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.
depends on how its done... and which CPU mode your inAm I right in thinking this is slower?
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:
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 switching1. Allocate a page table per process.
there isnt anything you need to do with your GDT specifically for separate address spaces2. Alter the GDT for different segments.
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)
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 spaces3. Every task switch I disabled the current page table and enable the next tasks one.
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
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.
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.
ya, sorry about thatYou 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.
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
yes... and you can still use them completely if you want but most people dont (its much more complicated to do so)I suppose segments are used for segmentation...? (Well duh!)
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
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)Can't I just XOR the current page table by 3 (011b) to disable it? And enable it with OR 3...?
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
quite broad indeed...Lastly... How do I map physical and virtual memory with paging? I realise this is quite broad...
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
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
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
yes and no...Can you tell me, am I correct in thinking that I can change the security ring level by changing the segment registers?
bits 0 & 1, for segment registers other than CS, is the RPL, which can only be used to downgrade, but not upgrade, your privilege levelThe next thing I'm wondering is how to stop it running code like:Code: Select all
cli mov ax, 0x10 mov es, ax hlt
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:
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)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...
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
- Combuster
- 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:
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)
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)