Some difficulties with trampoline code and linking.

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
pearmypie
Posts: 21
Joined: Sat Mar 01, 2025 8:06 pm
GitHub: https://github.com/ionutcatana

Some difficulties with trampoline code and linking.

Post by pearmypie »

Hello,

I am trying to write a higher half kernel for the RISC-V architecture, using OpenSBI. I need a portion of my code to run with paging off, create an initial page table (while keeping that portion identity mapped) and call `kmain`. This concept in itself is not unclear.

How do I accomplish this while keeping my code clean? Right now, I need to add GNU `__attribute__`s to all my functions and structs, which is error-prone. I've attached my linker script, as well as a visual :D representation of what I'm trying to accomplish below.

Should I compile & link the trampoline and kernel separately and concatenate them later?

Code: Select all

ENTRY(_start)
PHDRS
{
    boot    PT_LOAD FLAGS(5); /* r + e */
    text    PT_LOAD FLAGS(5); /* r + e */
    rodata  PT_LOAD FLAGS(4); /* r */
    data    PT_LOAD FLAGS(6); /* r + w */
    modules PT_LOAD FLAGS(4); /* r */
}

START_PADDR = 0x80200000 /* qemu's opensbi jumps here */
KERNEL_BASE_VADDR = 0xffffffffc0000000; /* last gib of the address space */

SECTIONS
{
    . = START_PADDR;

    PROVIDE(skernel_phys = .);

    /* physical = virtual */
    . = ALIGN(0x200000);
    .boot : {
        PROVIDE(sboot = .);
        KEEP(*(.text.boot))
        KEEP(*(.text.boot.*))
        KEEP(*(.rodata.boot))
        KEEP(*(.rodata.boot.*))
        KEEP(*(.data.boot))
        KEEP(*(.data.boot.*))
        KEEP(*(.bss.boot))
        KEEP(*(.bss.boot.*))
        PROVIDE(eboot = .);
    } : boot

    ASSERT(eboot - sboot < 0x200000, "boot section is too large");

    /* everything below is linked in the higher half */
    . = ALIGN(0x200000);
    . = KERNEL_BASE_VADDR;
    PROVIDE(skernel_virt = .);

    . = ALIGN(0x200000);
    .text : AT(ADDR(.text) - KERNEL_BASE_VADDR) {
        PROVIDE(stext = .);
        *(.text)
        *(.text.*)
        PROVIDE(etext = .);
    } : text

    ASSERT(etext - stext < 0x200000, "text section is too large");
    PROVIDE(stext_phys = ADDR(.text) - KERNEL_BASE_VADDR);

    . = ALIGN(0x200000);
    .rodata : AT(ADDR(.rodata) - KERNEL_BASE_VADDR) {
        PROVIDE(srodata = .);
        *(.srodata)
        *(.srodata.*)
        *(.rodata)
        *(.rodata.*)
        *(.sdata2)
        *(.sdata2.*)
        PROVIDE(erodata = .);
    } : rodata

    ASSERT(erodata - srodata < 0x200000, "rodata section is too large");
    PROVIDE(srodata_phys = ADDR(.rodata) - KERNEL_BASE_VADDR);

    . = ALIGN(0x200000);
    .data : AT(ADDR(.data) - KERNEL_BASE_VADDR) {
        PROVIDE(sdata = .);
        *(.sdata)
        *(.sdata.*)
        *(.data)
        *(.data.*)
        PROVIDE(sbss = .); /* this section needs to be zeroed out */
        *(.sbss)
        *(.sbss.*)
        *(.bss)
        *(.bss.*)
        *(COMMON)
        PROVIDE(ebss = .);
        PROVIDE(edata = .);
    } : data

    ASSERT(edata - sdata < 0x200000, "data section is too large");
    PROVIDE(sdata_phys = ADDR(.data) - KERNEL_BASE_VADDR);
    PROVIDE(sbss_phys = ADDR(.bss) - KERNEL_BASE_VADDR);

    /* user-space servers, drivers, init, or other boot modules */
    . = ALIGN(0x200000);
    .modules : AT(ADDR(.modules) - KERNEL_BASE_VADDR) {
        PROVIDE(smodules = .);
        KEEP(*(.modules))
        KEEP(*(.modules.*))
        PROVIDE(emodules = .);
    } : modules

    PROVIDE(smodules_phys = ADDR(.modules) - KERNEL_BASE_VADDR);
    PROVIDE(emodules_phys = emodules - KERNEL_BASE_VADDR);

    . = ALIGN(0x200000);
    PROVIDE(ekernel = .);
    PROVIDE(ekernel_phys = . - KERNEL_BASE_VADDR);

    /DISCARD/ : {
        *(.comment)
        *(.eh_frame)
        *(.eh_frame.*)
        *(.note)
        *(.note.*)
    }
}
Image
Octocontrabass
Member
Member
Posts: 6275
Joined: Mon Mar 25, 2013 7:01 pm

Re: Some difficulties with trampoline code and linking.

Post by Octocontrabass »

pearmypie wrote: ↑Fri Jun 12, 2026 9:43 amusing OpenSBI.
Personally, I would use U-Boot and write a normal UEFI bootloader, but that's because I'd want to reuse most of that code for other CPU architectures...
pearmypie wrote: ↑Fri Jun 12, 2026 9:43 amRight now, I need to add GNU `__attribute__`s to all my functions and structs, which is error-prone.
Do you? It seems like you could accomplish the same thing by compiling all of the boot code to its own object file and then instructing the linker to place only that object file in the boot section.
pearmypie wrote: ↑Fri Jun 12, 2026 9:43 amShould I compile & link the trampoline and kernel separately and concatenate them later?
That's the cleanest way of doing it. You can't accidentally mix up trampoline and kernel symbols if they're not linked together.
User avatar
pearmypie
Posts: 21
Joined: Sat Mar 01, 2025 8:06 pm
GitHub: https://github.com/ionutcatana

Re: Some difficulties with trampoline code and linking.

Post by pearmypie »

Code: Select all

other CPU architectures...
I wanted my project to be portable across RISC-V machines, though most of them do ship with u-boot in ROM, it might make more sense to write a UEFI bootloader, I will look into it.

Is this page a good starting point for u-boot?
Octocontrabass
Member
Member
Posts: 6275
Joined: Mon Mar 25, 2013 7:01 pm

Re: Some difficulties with trampoline code and linking.

Post by Octocontrabass »

pearmypie wrote: ↑Fri Jun 12, 2026 12:27 pmmost of them do ship with u-boot in ROM
U-Boot's UEFI support is an optional feature; I don't know if manufacturers usually enable it or not. It also only provides the EBBR subset of UEFI.
pearmypie wrote: ↑Fri Jun 12, 2026 12:27 pmIs this page a good starting point for u-boot?
It's... okay. You can use your normal bare-metal ELF cross-compiler instead of a Windows cross-compiler as long as you've built binutils with PE output support.
User avatar
pearmypie
Posts: 21
Joined: Sat Mar 01, 2025 8:06 pm
GitHub: https://github.com/ionutcatana

Re: Some difficulties with trampoline code and linking.

Post by pearmypie »

Maybe the `bootelf` command could be useful

Edit: I've never been more frustrated in my life. I will investigate going with `go` or `bootm` instead.
Post Reply