Page 1 of 2
Higher half and kernel linking
Posted: Thu Jun 02, 2011 6:40 pm
by Rusky
When initializing my kernel, I have a few things that need to happen: 1) paging needs to be enabled, 2) the physical memory manager needs to parse the memory map from grub, and 3) assorted startup code needs to access data that needs to stay there for later (e.g. the GDT, IDT, memory management structures).
The dependencies between these steps are driving me crazy. With higher-half, the kernel is linked at its virtual address and so the options options I've come up with are 1) enable paging in assembly, which would involve following all the multiboot pointers (in assembly) so they'll still be accessible to the physical memory manager and then later unmapping them all, 2) link the startup code at its physical address and then do some pointer manipulation to access kernel structures at their physical addresses as well, or 3) don't use a higher-half kernel.
Also involved is bootstrapping the physical memory manager without knowing the amount of physical memory at compile time. I'm pretty sure I have to either carefully avoid all the multiboot structures when allocating the first structures, or use them all first and then don't worry about overwriting them (although I'd still have to deal with modules and this approach probably involves copying the multiboot tables to a known location as I need them while setting up the physical memory manager).
These problems are why I've avoided a higher half kernel up to now. Does anyone have a good system for resolving these dependencies? Maybe some variation on the GDT trick to access both the kernel at its linked/virtual address and the multiboot tables at their physical address, or using some kind of pre-defined page tables that avoid the problems above, maybe involving PSE?
Re: Higher half and kernel linking
Posted: Thu Jun 02, 2011 8:04 pm
by neon
Hello,
System data structures (GDT,IDT) can and should be setup during kernel initialization -- before or after memory management. So all of (3) can be setup later on. By having the kernel copy the data structures used by Grub locally (on a stack), the memory manager can work off of this copy without error.
This is what we do with regards to enabling paging: We link using a virtual base address but tell the bootloader to load it to a physical address and call it there. Enabling paging must then be done using position independent code.
Re: Higher half and kernel linking
Posted: Fri Jun 03, 2011 1:10 am
by xenos
In my
linker script I reserve some space for the GDT, IDT, page tables and so on. When GRUB loads my kernel, it reads the ELF header and keeps its data structures (multiboot info, memory map, modules...) out of the reserved space. The
startup code can then simply fill the reseved space with GDT, IDT and so on, without trashing any important data.
Re: Higher half and kernel linking
Posted: Fri Jun 03, 2011 6:50 am
by egos
It's bad idea.
Re: Higher half and kernel linking
Posted: Fri Jun 03, 2011 6:51 am
by Combuster
It's bad idea.
proof wanted.
Re: Higher half and kernel linking
Posted: Fri Jun 03, 2011 11:16 am
by egos
A "higher-half userspace" requires to store fixup information into application executable module and relocate it (in most cases) if kernel space resizing allowed.
To topic starter: maybe to use "binary" output format (instead ELF) is better solution for you.
Re: Higher half and kernel linking
Posted: Fri Jun 03, 2011 1:46 pm
by Rusky
I think I'm going with a small, identity-mapped startup routine where I'll copy the MBI to a temporary heap, enable paging with temporary page tables, and then initialize the rest (with the physical memory manager accessing the copied MBI and running from its virtual address).
Flat binaries would just make things more complicated in this case, because GRUB already understands ELF section physical addresses.
Re: Higher half and kernel linking
Posted: Fri Jun 03, 2011 1:59 pm
by egos
berkus wrote:1G/3G kernel/user split is no different from 3G/1G user/kernel split, although slightly simpler (no need to remap low memory).
They differ from one another. What fixed base address should user space have for 1G/2G kernel space? 2G? If so then no reason to have kernel space smaller than with size 2G. And what can I do if I shall have experimental kernel with 3G space?
Re: Higher half and kernel linking
Posted: Fri Jun 03, 2011 2:04 pm
by Velko
I use something similar to XenOS's method - reserve some space (128K I think) at the end of kernel using linker script. Then with help of one extra variable it's easy (even in assembly) to "grab" some pages for stack, PD, PT, etc. from there.
What remains after "grabbing" is handed over to kmalloc(). And memory for GDT, IDT and whatever else I need is kmalloc()ated.
Re: Higher half and kernel linking
Posted: Fri Jun 03, 2011 2:29 pm
by egos
Rusky wrote:Flat binaries would just make things more complicated in this case, because GRUB already understands ELF section physical addresses.
Well, if you want to use complicated ELF instead complicated "binary" format, it's your business. GRUB uses one type of section address (not physical and virtual separately) to load sections into memory at physical addresses.
Re: Higher half and kernel linking
Posted: Sat Jun 04, 2011 10:36 am
by Rusky
egos wrote:Well, if you want to use complicated ELF instead complicated "binary" format, it's your business. GRUB uses one type of section address (not physical and virtual separately) to load sections into memory at physical addresses.
ELF is complicated, sure, but GRUB handles it all for you. I
need separate physical and virtual addresses for whichever format I use, to tell the linker where code should run and to tell GRUB where it should be loaded, so switching to flat binaries would introduce more complexity on my end.
A higher-half kernel seems like a good idea to me, since growing it down would just move the application's stack, not its code. The stack is just a run-time pointer, but moving code means recompiling or relocating. It's not all that important, but I need the mechanisms to set up a higher-half kernel anyway, and whether I should use higher-half wasn't even the question here.
One other question I
do have is how to deal with code that needs to run both before and after initialization- mostly the strings library with strlen, strcpy, memcpy, etc. Is there a good way to duplicate those functions into the init section and then get things to link correctly?
Re: Higher half and kernel linking
Posted: Sat Jun 04, 2011 11:06 am
by bluemoon
strlen, strcpy, memcpy, etc should be easy to code as position independent.
Then the question is how to call the function with proper address.
You can link them as virtual address,
to call it before paging is enabled (which I don't see a need), you can use a macro to translate it to physical address, eg.
Code: Select all
%define PhysicalAddress(x) ((x) - kernel_base)
call PhysicalAddress(strlen)
OR
%define phy_strlen (strlen - kernel_base)
call phy_strlen
after paging is initialized you call the function as usual.
Re: Higher half and kernel linking
Posted: Sat Jun 04, 2011 11:30 am
by Chandra
Rusky wrote:The dependencies between these steps are driving me crazy. With higher-half, the kernel is linked at its virtual address and so the options options I've come up with are 1) enable paging in assembly, which would involve following all the multiboot pointers (in assembly) so they'll still be accessible to the physical memory manager and then later unmapping them all, 2) link the startup code at its physical address and then do some pointer manipulation to access kernel structures at their physical addresses as well, or 3) don't use a higher-half kernel.
I like the third option.
Re: Higher half and kernel linking
Posted: Sat Jun 04, 2011 12:11 pm
by Owen
4) The kernel binary contains paging structures to map itself, and a page table into which temporary mappings can be placed. As you walk the Multiboot structures, map and unmap them from this table as needed
Re: Higher half and kernel linking
Posted: Sat Jun 04, 2011 1:14 pm
by Rusky
Shall we move past the higher-half debate?
It's simpler to copy the multiboot structures- the question is how to call the string functions. I think it should work to just make some static const function pointers in the C startup code that needs to call the string library, but they'd need to use different names...?