How to use kernel functions on early stage?
-
- Posts: 6
- Joined: Sat Dec 03, 2022 7:54 am
How to use kernel functions on early stage?
Hello everyone. I have written higher half kernel for x86_64 UEFI platform with GRUB as a bootloader. It works, but I have one problem. I can't use printk function from the kernel on the early stage that creates new page tables to move kernel to the higher half, because it is counting on it runs on the higher half. My question: is there a good way to use printk from the kernel or copy its content and relink with address on which the early stage executes? Or should i just copy all the code to another .c file, rename printk in it to something like early_printk and use early_printk on the early stage?
Re: How to use kernel functions on early stage?
I have separated the pre-paging part of the kernel into its own executable, partially because of issues like this. Now the debug code can be linked into both of them as needed. It is not a drain on resources as the pre-paging part can just be freed once the main kernel is running.
Carpe diem!
-
- Posts: 6
- Joined: Sat Dec 03, 2022 7:54 am
Re: How to use kernel functions on early stage?
Yes, I though about that, I just hope there is a simpler way to do it. Because it means to write my own ELF loader, it's not hard, but still takes time. It seems I have to do it. Thank you!
Re: How to use kernel functions on early stage?
Not necessarily. The pre-paging executable can just contain exactly the code you have now, and then the main kernel as a data item (in .rodata). Or, since you say you are booting with GRUB, GRUB supports loading modules, so you can get GRUB to load the pre-paging stuff as main kernel and the main kernel as module. That is actually how I implement legacy booting with GRUB.
Carpe diem!
-
- Posts: 6
- Joined: Sat Dec 03, 2022 7:54 am
Re: How to use kernel functions on early stage?
A solution with main kernel as a module sounds interesting, I try to implement it
-
- Member
- Posts: 442
- Joined: Tue Apr 03, 2018 2:44 am
Re: How to use kernel functions on early stage?
I find it easier to just have a single kernel image, but with different sections linked to different base addresses.cyberfined wrote: ↑Sun Apr 06, 2025 5:09 am A solution with main kernel as a module sounds interesting, I try to implement it
I have a .bootstrap_code, .bootstrap_data, .bootstrap_stack and .bootstrap_pgtbl (he latter two are page sized/aligned), and the bootstrap environment that sets up the kernel runtime page table for higher half operation is linked and run in the lower half of memory accessible to the bootloader.
Then I just have regular .text, .data etc sections for my kernel, which are linked into the higher half at the kernel runtime address. Once the bootstrap code has setup the initial runtime page table, I jump to the kernel proper.
As an added benefit, because the bootstrap code and data are page sized and aligned, I can just reuse their pages in the pool of free pages, they're no longer used after bootstrap.
Linker script fragment:
Code: Select all
/* Begin putting sections at 1 MiB, a conventional place for kernels to be
loaded at by the bootloader. */
. = 1M;
_bootstrap_start = .;
/* First put the multiboot header, as it is required to be put very early
early in the image or the bootloader won't recognize the file format. */
.bootstrap :
{
*(.bootstrap_data)
*(.bootstrap_code)
}
.bootstrap_aligned ALIGN(4K) :
{
*(.bootstrap_stack)
*(.bootstrap_pgtbl)
}
/* Rest of the kernel lives in high memory */
_kernel_offset_bootstrap = .;
. += kernel_offset;
_kernel_offset = .;
/* Next we'll put the .text section. */
.text ALIGN(4K) : AT(ADDR(.text) - kernel_offset)
{
code_start = .;
*(.text)
code_end = .;
}