Loading a long mode kernel
Posted: Thu Jun 23, 2016 3:14 pm
I've just read the multiboot spec and I'm trying to figure exactly how to load a kernel in long mode. I can already successfully switch the CPU into long mode as long as the virtual address to physical address is the identity function. I would like my memory layout to consist of the following during the execution of a process:
1. Kernel memory at the top (this memory mapping would always be fixed). Let's call this KERNEL_BASE_ADDR.
2. User stack growing down
3. Heap growing up
4. Data
5. Userland code
The purpose of this question is how to get the kernel up there. In particular, how to set up linker scripts and the assembly files, so that generated code is made relative to the correct address where it's going to sit (virtual address that is).
In principle it's all very easy and I would need GRUB to load things up as follows:
1. Multiboot header + initial code which sets up page table and switches to long mode.
2. Followed by code with .code64 specifier aligned to a 4KB page boundary.
Essentially,. I would just like to map the virtual address KERNEL_BASE_ADDR to the physical address where (2) sits and then jump to that code to get myself up and running. I can easily have a linker.ld like:
where .multiboot_header is a section containing those magic values and .text contains the 32-bit code that sets up the CPU long mode. Where should I then put the "pure" 64-bit code and how do I generate code that thinks it's loaded at address KERNER_BASE_ADDR when GRUB has to simultaneously load it at a different physical address?
I'm using the GNU assembler.
1. Kernel memory at the top (this memory mapping would always be fixed). Let's call this KERNEL_BASE_ADDR.
2. User stack growing down
3. Heap growing up
4. Data
5. Userland code
The purpose of this question is how to get the kernel up there. In particular, how to set up linker scripts and the assembly files, so that generated code is made relative to the correct address where it's going to sit (virtual address that is).
In principle it's all very easy and I would need GRUB to load things up as follows:
1. Multiboot header + initial code which sets up page table and switches to long mode.
2. Followed by code with .code64 specifier aligned to a 4KB page boundary.
Essentially,. I would just like to map the virtual address KERNEL_BASE_ADDR to the physical address where (2) sits and then jump to that code to get myself up and running. I can easily have a linker.ld like:
Code: Select all
ENTRY(start)
SECTIONS {
. = 1M;
.text :
{
/* ensure that the multiboot header is at the beginning */
*(.multiboot_header)
*(.text)
}
}
I'm using the GNU assembler.