ajhahn.de
← FlashOS
plain text 87 lines
/*
 * Kernel link script (RPi4, AArch64).
 * PID 1 is ELF-loaded from the embedded initramfs:
 * `/sbin/init` is the standalone `pid1.elf` artifact, and
 * the kernel's `prepare_move_to_user_elf` maps it page-grain. The
 * `user_init.o` blob — wrapped here in `.text.user` /
 * `.rodata.user` / `.data.user` / `.bss.user` between `user_start`
 * and `user_end` — is retired.
 */

SECTIONS
{
    /DISCARD/ : { *(.eh_frame) *(.eh_frame_hdr) *(.note.*) *(.comment) }

    /* RPi4 firmware loads kernel8.img at PA 0x80000 (the standard AArch64
     * load address; see "Kernel relocated to 0x80000" in start4.elf log).
     * Linking at the same base means linker-resolved global pointers
     * actually point at the bytes the firmware placed — no relocator
     * needed at boot. Previously the implicit base was 0x01000000, which
     * sat above the 16 MB id-map and caused L2 translation faults the
     * moment any global was dereferenced (e.g. ksyms in cal_ksyms_count). */
    . = 0x80000;

    .text.boot : { *(.text.boot) *(.text.boot.late) *(.text.boot.literals) }
    .text : {
        *(.text)
        *(.text.*)
    }
    .rodata : {
        *(.rodata)
        *(.rodata.*)
    }
    .data : {
        *(.data)
        *(.data.*)
    }

    . = ALIGN(0x8);
    __start_patchable_functions = .;
    .patchable_function_entries : {
        KEEP(*(__patchable_function_entries))
    }
    __stop_patchable_functions = .;

    . = ALIGN(0x8);
    ksyms = .;
    symbols : {
        KEEP(*(_symbols))
    }

    . = ALIGN(0x8);
    bss_begin = .;
    .bss : {
        *(.bss)
        *(.bss.*)
        *(COMMON)
    }
    bss_end = .;

    /* Embedded initramfs. Placed between bss_end and
     * id_pg_dir; the kernel reads it through a TTBR1 linear-map
     * alias in src/initramfs.zig. Size shifts everything past it
     * (id_pg_dir, high_pg_dir), so the cpio bytes must be a
     * deterministic function of the source tree (see
     * scripts/build_initramfs.zig for the deterministic encoder). */
    . = ALIGN(0x4);
    .initramfs : {
        KEEP(*(.initramfs))
    }

    . = ALIGN(0x1000);
    id_pg_dir = .;
    .data.id_pg_dir : { . += (3 * (1 << 12)); }
    high_pg_dir = .;
    .data.high_pg_dir : { . += (6 * (1 << 12)); }

    /* End-of-reserved-PA marker for the get_free_page pool. Read by
     * mem_map_reserve_below in kernel_main so the allocator never hands
     * out a PA inside the kernel image / page-table reservations. On
     * RPi4 the kernel sits at PA 0x80000–~0x200000, far below the
     * pool's MALLOC_START (0x40000000), so the reserved range is empty
     * and reserve_below is a no-op — but the symbol is still defined
     * for cross-board parity with virt. */
    . = ALIGN(0x1000);
    _kernel_pa_end = .;
}