Royce Mitchell III wrote:
Finally, there seems to be quite a bit of disagreement about who should relocate ntoskrnl, so I might be wasting my effort trying to get this to actually work, except for the learning value of it all.
I can't see why there should be any disagreement about this. The only logical piece of code to relocate it, is the same piece of code that loads it. Having the kernel relocate itself, while it is running from/in the very image that is to be relocated (!) is not only a bit tricky (http://svn.reactos.com/viewcvs/trunk/msvc6/ntoskrnl/ke_i386_multiboot.c?rev =8046), it's also quite fragile. Should some, any, little piece be changed like code injected or moved to prohibit short function call addressing, it will crash. Should anyone ever make a change in the belief they could access global data (like one usually can from a program), it will crash. Should the very critical link-order change, making the multiboot table i the binary move to outside the first 8192 bytes if the on-disk image, it will crash.
A PE binary normally knows nothing, and shouldn't (have to) know anything, about its on-disk binary stored format. It already has an entry in the PE header telling what/where the entrypoint of the program is. Multiboot on the other hand uses absolute physical addresses, including the entrypoint address (that doesn't even need to point to within the image itself) that it reads from the multiboot-header in the binary. There is no portable way for a PE binary to know at what physical offset from the start of the binary on-disk image a particular piece of code will be without knowing _exactly_ how the linker will place stuff in the on-disk image at compile-time. Linker. Compile-time. Let it sink in a bit.
Having this hard-coded relationship between multiboot and ntoskrnl.exe makes porting harder and the kernel code harder to understand (and therefore maintain).
Should on the other hand the following steps be taken, the ntoskrnl code would become cleaner, more portable and follow logic (that the one doing the loading, also does the relocation) to a much greater degree. The binary image would also no longer contain redundant (and possibly contradictory) information re. where its entry function is, as is the case today.
1. Have a binary that loads the kernel, hal, and the boot drivers into memory. This is done today by freeloader.
2. Have that very same binary do the PE (-section) relocation of these images, including clearing uninitialized data segments as usual for bss (be it explicit as in MinGW built images, or as the "slack" between initialized and virtual size in a/the data section as images built with e.g. MSVC). This is well-known and not very complicated.
3. Have the boot-loader know whether or not /3G is present. This allows _it_ to set up the architecture-specific initial page-table mappings. The benefit of this is, as I see it, that the boot loader is by necessity a very architecture specific piece of code, why it might as well follow what ntldr does. The kernel image would then, when it gets control, already be at the virtual address it's supposed to be, and it can freely access global data as it should have been able to do in the first place. This also has the obvious benefit that much of the _highly_ architecture-specific code can be removed from the kernel itself.
That last point should really be the only argument that's needed.
/Mike