Avoid relocation issues with segmentation
Avoid relocation issues with segmentation
I know this is not an approach most would take, but I'm wondering if this is feasible:
The GDT has space for 8192 entries.. would it be possible to fill ALL of them with code/data descriptors when doing LGDT and leaving the address at 00000000h.
Then when you need to load a library, executable, start a process or thread the kernel could pick the next free GDT entries, set the addresses as to where in physical mem it loaded the code/data and then by using that as a form of segmentation model (this is assuming we're not making any use of paging) each executable / library could assume it's offsets are all zero based.
The only limitations I can see doing it this way would be a max of about 1024 running processes/threads as each would need 3 descriptors for CS/DS/SS. The idea i had in mind is that a) my user apps all run at ring0 and they also have direct access to the list of selections / GDT / IDT entries etc.. so the app could setup ES/FS with any of the available OS provided selectors.. possibly even ones mapped for PCI device mem/io spaces?
Obviously to allow user apps / libs etc to call functions and code in the kernel (having it's own code/data/stack descriptors) would require one of 3 options... A) cross selector call from app CS sel to kernel CS sel
Not sure how that would work... or B) the OS would provide a call-table based on actual physical addresses of the routines then the app could use the zero-based selector to call them... or C) use the app's CS selector but possibly apply a negative offset if the routine's phys. addr is below the selector?(not sure if thats possible)
Anyone have any thoughts on that model?
The GDT has space for 8192 entries.. would it be possible to fill ALL of them with code/data descriptors when doing LGDT and leaving the address at 00000000h.
Then when you need to load a library, executable, start a process or thread the kernel could pick the next free GDT entries, set the addresses as to where in physical mem it loaded the code/data and then by using that as a form of segmentation model (this is assuming we're not making any use of paging) each executable / library could assume it's offsets are all zero based.
The only limitations I can see doing it this way would be a max of about 1024 running processes/threads as each would need 3 descriptors for CS/DS/SS. The idea i had in mind is that a) my user apps all run at ring0 and they also have direct access to the list of selections / GDT / IDT entries etc.. so the app could setup ES/FS with any of the available OS provided selectors.. possibly even ones mapped for PCI device mem/io spaces?
Obviously to allow user apps / libs etc to call functions and code in the kernel (having it's own code/data/stack descriptors) would require one of 3 options... A) cross selector call from app CS sel to kernel CS sel
Not sure how that would work... or B) the OS would provide a call-table based on actual physical addresses of the routines then the app could use the zero-based selector to call them... or C) use the app's CS selector but possibly apply a negative offset if the routine's phys. addr is below the selector?(not sure if thats possible)
Anyone have any thoughts on that model?
Re: Avoid relocation issues with segmentation
Interesting, thanks for the information!
I wonder if it would be possible to migrate that same technique to long mode/64bit given it's segmentation restrictions. Would it still be possible to use the GDT entries with different physical addresses and swap between them?
I wonder if it would be possible to migrate that same technique to long mode/64bit given it's segmentation restrictions. Would it still be possible to use the GDT entries with different physical addresses and swap between them?
Re: Avoid relocation issues with segmentation
Hi,
Cheers,
Brendan
The same descriptor can be used for DS and SS, so you'd be limited to about 4000 processes. There's plenty of ways around that though, like creating/modifying GDT entries dynamically (which you need to do anyway if you want to prevent one process from being able to trash another).johnsa wrote:The only limitations I can see doing it this way would be a max of about 1024 running processes/threads as each would need 3 descriptors for CS/DS/SS.
It would be entirely possible to use the same technique for 32-bit processes running under a long mode/64-bit kernel. For 64-bit processes running under a long mode/64-bit kernel you can't use segments (the base address and limit is ignored) so you'd need to use some other method (e.g. position independent code, JIT, etc)johnsa wrote:I wonder if it would be possible to migrate that same technique to long mode/64bit given it's segmentation restrictions. Would it still be possible to use the GDT entries with different physical addresses and swap between them?
Everyone that's been too lazy to figure out how to use paging properly has thought about using segmentation as a half-assed obsolete alternative...johnsa wrote:Anyone have any thoughts on that model?
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re: Avoid relocation issues with segmentation
Lol.. true I guess. TBH the whole paging thing can be quite confusing, the basics are fine.. enabling it and setting up an initial dir/pg.tbls.. but how to use it there-after effectively is where the tricky bit comes.
My issue is how I would use paging and still meet one of the design criteria I have for my project which is that every application can access the OS/physical memory in a direct and straight-forward manner.
For example.. suppose the Kernel sets up the video card and configures it.. it may provide a set of functions like mode enumeration/set/bit-blt etc, but I would like to be able to have the application obtain a ptr to the frame-buffer and do with the video what it will. In essence I'm trying to have a system which is as open-ended as things were in the old days / ala dos but with support for modern standards, devices, buses etc.
Paging will make the Oses life easier, but will complicate things from the app's point of view.
Also how would paging work with software switching/no tss or ldt.. must every app have it's own full 4mbs worth of page-table specific to it and this gets swapped every task-switch?
My issue is how I would use paging and still meet one of the design criteria I have for my project which is that every application can access the OS/physical memory in a direct and straight-forward manner.
For example.. suppose the Kernel sets up the video card and configures it.. it may provide a set of functions like mode enumeration/set/bit-blt etc, but I would like to be able to have the application obtain a ptr to the frame-buffer and do with the video what it will. In essence I'm trying to have a system which is as open-ended as things were in the old days / ala dos but with support for modern standards, devices, buses etc.
Paging will make the Oses life easier, but will complicate things from the app's point of view.
Also how would paging work with software switching/no tss or ldt.. must every app have it's own full 4mbs worth of page-table specific to it and this gets swapped every task-switch?
Re: Avoid relocation issues with segmentation
Hi,
For the video frame buffer/s, the kernel could choose a (virtual) address to map each video card's frame buffer that's the same for every application, or each application can ask the kernel to map any video card's frame buffer at any (virtual) address it likes.
Cheers,
Brendan
Not really - being forced to use segmentation when most compilers don't support it might complicate applications though...johnsa wrote:Paging will make the Oses life easier, but will complicate things from the app's point of view.
For the video frame buffer/s, the kernel could choose a (virtual) address to map each video card's frame buffer that's the same for every application, or each application can ask the kernel to map any video card's frame buffer at any (virtual) address it likes.
It'd make very little difference to software task switching, except you might not need to save/restore segment registers during task switches and you probably would need to change CR3 during task switches.johnsa wrote:Also how would paging work with software switching/no tss or ldt.. must every app have it's own full 4mbs worth of page-table specific to it and this gets swapped every task-switch?
Cheers,
Brendan
For all things; perfection is, and will always remain, impossible to achieve in practice. However; by striving for perfection we create things that are as perfect as practically possible. Let the pursuit of perfection be our guide.
Re: Avoid relocation issues with segmentation
Hmm.. ok, now I'm a bit confused...
GDT/IDT entries are physical addresses, paging has no affect on their contents correct?
Or is that incorrect.. once paging is enabled the base of the gdt entry gets mapped via the page tables again?
Assuming you're using normal 4kb pages, you need say 4Mb to store the page dir/tbls... and now would EVERY application need it's own 4Mb of page-tables?? seems like a huge waste of memory.. plus every task switch reloading CR3 would invalidate TLB, caches and such .. couldn't this cause major performance issues while switching?
Clearly my knowledge of paging is a bit rough.. lol.. I'm struggling to see how multiple processes could each have unique paging setups without wasting HUGE amounts of memory and having to reload cr3 every switch
GDT/IDT entries are physical addresses, paging has no affect on their contents correct?
Or is that incorrect.. once paging is enabled the base of the gdt entry gets mapped via the page tables again?
Assuming you're using normal 4kb pages, you need say 4Mb to store the page dir/tbls... and now would EVERY application need it's own 4Mb of page-tables?? seems like a huge waste of memory.. plus every task switch reloading CR3 would invalidate TLB, caches and such .. couldn't this cause major performance issues while switching?
Clearly my knowledge of paging is a bit rough.. lol.. I'm struggling to see how multiple processes could each have unique paging setups without wasting HUGE amounts of memory and having to reload cr3 every switch
-
- Member
- Posts: 524
- Joined: Sun Nov 09, 2008 2:55 am
- Location: Pennsylvania, USA
Re: Avoid relocation issues with segmentation
Nope, GDT entries are linear addresses, not physical. Segmentation is implemented on top of paging.GDT/IDT entries are physical addresses, paging has no affect on their contents correct?
Or is that incorrect.. once paging is enabled the base of the gdt entry gets mapped via the page tables again?
Re: Avoid relocation issues with segmentation
Ok so let me follow through a process here...
Kernel sets up paging, it sets up a page dir/page tables mapping physical->linear memory in a transparent fashion so that it can easily find physical resources.
So we start off with CR3 pointing to this (paging linear = physical model).
Kernel decides to load an application. It selects (For example) location 0x9c4000 (10Mb) and loads the app there.
Now it has to create NEW page dir/page tables that map linear->physical so that that 0x00000000 = 0x9c4000.
Once it's create these, it updates CR3 to point to these new tables at which point essentially the kernel is now using the APPs address-space, so it would do for example a call to 0x00000000 to start the app.
The app runs for 10ms and the scheduler kicks in (for eg. using PIT) and the PIT code is now called. Now this code is essentially system/kernel code that should updated back to using the kernels true linear->physical map.. but the machine is still stuck in the app's address space mapping? whats the best way to ensure that the kernel page dir/tables are ALWAYS available in every space to be reloaded into CR3, just map the table's physical location into each address space too?
Also .. this still doesn't answer my question about having to have multiple sets of 4Mb tables all the time... If i had 10 apps running that would be 40Mb of mem!?!?
Kernel sets up paging, it sets up a page dir/page tables mapping physical->linear memory in a transparent fashion so that it can easily find physical resources.
So we start off with CR3 pointing to this (paging linear = physical model).
Kernel decides to load an application. It selects (For example) location 0x9c4000 (10Mb) and loads the app there.
Now it has to create NEW page dir/page tables that map linear->physical so that that 0x00000000 = 0x9c4000.
Once it's create these, it updates CR3 to point to these new tables at which point essentially the kernel is now using the APPs address-space, so it would do for example a call to 0x00000000 to start the app.
The app runs for 10ms and the scheduler kicks in (for eg. using PIT) and the PIT code is now called. Now this code is essentially system/kernel code that should updated back to using the kernels true linear->physical map.. but the machine is still stuck in the app's address space mapping? whats the best way to ensure that the kernel page dir/tables are ALWAYS available in every space to be reloaded into CR3, just map the table's physical location into each address space too?
Also .. this still doesn't answer my question about having to have multiple sets of 4Mb tables all the time... If i had 10 apps running that would be 40Mb of mem!?!?
- Firestryke31
- Member
- Posts: 550
- Joined: Sat Nov 29, 2008 1:07 pm
- Location: Throw a dart at central Texas
- Contact:
Re: Avoid relocation issues with segmentation
Remember, there's nothing saying you have to allocate the entire paging tree immediately. It's set up in a way that you can allocate and use bits and pieces at different times, namely the ability to specify where in physical memory the page dir/table/whatever is. So you could allocate the page directory and single page table, and 2 pages (one for code and one for data) and only use 16k per process. Then if a process wants more just insert more pages/page tables as needed.
Owner of Fawkes Software.
Wierd Al wrote: You think your Commodore 64 is really neato,
What kind of chip you got in there, a Dorito?
- xenos
- Member
- Posts: 1121
- Joined: Thu Aug 11, 2005 11:00 pm
- Libera.chat IRC: xenos1984
- Location: Tartu, Estonia
- Contact:
Re: Avoid relocation issues with segmentation
Yes, that's the standard way to do this. The kernel (and, thus, interrupt handlers) is mapped to a fixed linear address, in every address space. So no matter which address space is used, the kernel can always be found at the same linear address.johnsa wrote:The app runs for 10ms and the scheduler kicks in (for eg. using PIT) and the PIT code is now called. Now this code is essentially system/kernel code that should updated back to using the kernels true linear->physical map.. but the machine is still stuck in the app's address space mapping? whats the best way to ensure that the kernel page dir/tables are ALWAYS available in every space to be reloaded into CR3, just map the table's physical location into each address space too?
No, you don't have to waste that much memory. For each address space, you need:Also .. this still doesn't answer my question about having to have multiple sets of 4Mb tables all the time... If i had 10 apps running that would be 40Mb of mem!?!?
- A page directory. That's a 4kB page, holding 1024 pointers to the page tables physical addresses. BUT: If you set the "present" bit of one of these entries to 0, the processor knows that there is no page table for that address.
- Page tables for allocated user space. You only need to provide page tables for linear addresses that are actually used. Unused addresses don't need a page table. Just clear the "present" flag in the page directory.
- A mapping of kernel space. You don't need extra page tables for this. Just enter the kernel page tables into the user page directory.
Re: Avoid relocation issues with segmentation
Ok so that makes sense in that one could have much smaller tables and just be smart about how you construct them for each process.
As for mapping the kernel into the applications space this yields another question...
lets assume that the kernel was compiled to assume that it's loaded to 0x00000000. In a classic pmode / 32 system one would create a GDT with entries for kernel code/data/stack which reflect the base to which it's actually loaded in memory and the kernel's code can then work assuming 0-based offsets.
Now we load a process, setup the paging and map the kernel into that space.. but since the kernel's code expects everything to be 0-relative, the only place we could map it and it would still work is to 0.. which means the application code/data would have to be mapped to another linear address which is constant, say 2gig within it's 4gb linear space... so once in the app's space we've got the kernel from 0-2gig, app code data 2gig-4gig ... (or 2gig+ if its 64bit).. and thusly ALL applications would be compiled with an assumed base address of 0x7A120000 (2gig)..
Obviously this could apply the other way where the kernel must assume its base is something else and the app's is 0.. but that leads to problems accessing the kernel before paging is setup?
I guess we'd also want to ensure that in the 0-2gig space there is enough room then to map in the other things like frame-buffer etc that it might want to access?
Is that the right process to follow, or am I missing something about how the kernel/app should operate in the same linear space when they both need to be compiled with fixed bases?
As for mapping the kernel into the applications space this yields another question...
lets assume that the kernel was compiled to assume that it's loaded to 0x00000000. In a classic pmode / 32 system one would create a GDT with entries for kernel code/data/stack which reflect the base to which it's actually loaded in memory and the kernel's code can then work assuming 0-based offsets.
Now we load a process, setup the paging and map the kernel into that space.. but since the kernel's code expects everything to be 0-relative, the only place we could map it and it would still work is to 0.. which means the application code/data would have to be mapped to another linear address which is constant, say 2gig within it's 4gb linear space... so once in the app's space we've got the kernel from 0-2gig, app code data 2gig-4gig ... (or 2gig+ if its 64bit).. and thusly ALL applications would be compiled with an assumed base address of 0x7A120000 (2gig)..
Obviously this could apply the other way where the kernel must assume its base is something else and the app's is 0.. but that leads to problems accessing the kernel before paging is setup?
I guess we'd also want to ensure that in the 0-2gig space there is enough room then to map in the other things like frame-buffer etc that it might want to access?
Is that the right process to follow, or am I missing something about how the kernel/app should operate in the same linear space when they both need to be compiled with fixed bases?
Re: Avoid relocation issues with segmentation
Hey,
Ok, re-read those tuts and saw how the linkage is setup to work in higher-half (3gig) using both paging or gdt tweak.
Now here comes my next (possibly silly question):
Assuming then the Kernel is designed / linked to be at 0xC0000000:
The kernel is loaded to 0x100000 and then mapped via paging to appear at the above address.
This would now assume that 0x0 - 0xC0000000 is available as the user space and 3Gig up to 4Gig is for the kernel, drivers, mapped in data etc.
Assume now that we want to map things like the frame-buffer etc into the user apps address space... it's quite possible that once all tables and frame-buffers and audio buffers and pci config space etc are mapped in that along with the Kernel it would require more than 1gig.. IE: SLI video cards? or 1 card with a gig of mem.. so that higher-half mapping would no longer be suitable (depending on system config). We would have to make hacks and load some of that stuff below the 3Gig mark? could lead to wholes and wasted memory etc.
I am thinking of skipping 32bit altogether to be honest and going for a 64bit kernel straight away. As it's for my own enjoyment and all the machines I have support 64bit, and so would any other machine I'd ever considering running it on.. might as well embrace the future and go64 That being said... the 3Gig mark is now fairly arbitrary.. In 64bit long mode what would be a better option? to avoid the above mentioned problems.. and assuming that now we could have more than 4gig addressable linearly.. so having a chunk eaten out at 3gig could be a bit of a waste possibly?
Ok, re-read those tuts and saw how the linkage is setup to work in higher-half (3gig) using both paging or gdt tweak.
Now here comes my next (possibly silly question):
Assuming then the Kernel is designed / linked to be at 0xC0000000:
The kernel is loaded to 0x100000 and then mapped via paging to appear at the above address.
This would now assume that 0x0 - 0xC0000000 is available as the user space and 3Gig up to 4Gig is for the kernel, drivers, mapped in data etc.
Assume now that we want to map things like the frame-buffer etc into the user apps address space... it's quite possible that once all tables and frame-buffers and audio buffers and pci config space etc are mapped in that along with the Kernel it would require more than 1gig.. IE: SLI video cards? or 1 card with a gig of mem.. so that higher-half mapping would no longer be suitable (depending on system config). We would have to make hacks and load some of that stuff below the 3Gig mark? could lead to wholes and wasted memory etc.
I am thinking of skipping 32bit altogether to be honest and going for a 64bit kernel straight away. As it's for my own enjoyment and all the machines I have support 64bit, and so would any other machine I'd ever considering running it on.. might as well embrace the future and go64 That being said... the 3Gig mark is now fairly arbitrary.. In 64bit long mode what would be a better option? to avoid the above mentioned problems.. and assuming that now we could have more than 4gig addressable linearly.. so having a chunk eaten out at 3gig could be a bit of a waste possibly?
Re: Avoid relocation issues with segmentation
Speaking of which, do bochs and qemu support 64bit code/longmode etc?
- 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:
Re: Avoid relocation issues with segmentation
Have you even bothered to check?
Re: Avoid relocation issues with segmentation
Yes... I know they "do" support 64bit code.. but the question was more a case of.. how well, is it solid enough under qemu/bochs to really test with.