blob: 54f619c288e36c3f51eecbec1643ceda58a8a52d (
plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
/* SPDX-License-Identifier: GPL-2.0-or-later */
/* Copyright (C) 2026 Richard Qin */
/*
* LumeOS Kernel Linker Script
*
* Memory Layout (SV39 Higher-Half Kernel):
* Virtual Base: 0xFFFFFFC080200000
* Physical Base: 0x80200000
* VA-PA Offset: 0xFFFFFFC000000000 (PAGE_OFFSET)
*
* The AT() directives produce correct LMA (Load Memory Address) so the
* bootloader loads sections at their physical addresses while the kernel
* code references their virtual addresses.
*
* Reference: docs/specs/linker_and_entry.md
*/
OUTPUT_ARCH(riscv)
PAGE_OFFSET = 0xFFFFFFC000000000;
BASE_ADDRESS = 0xFFFFFFC080200000;
PHYS_BASE = 0x80200000;
/* ELF entry point must be the PHYSICAL address because OpenSBI/QEMU
* jumps to it before MMU is enabled. _start is at VMA, so we use
* the computed physical equivalent. */
ENTRY(_start)
SECTIONS {
. = BASE_ADDRESS;
/* ===== .head.text: Image Header (must be at byte 0) ===== */
.head.text : AT(PHYS_BASE) {
_start = .;
KEEP(*(.head.text))
}
/* ===== .text: Executable Code ===== */
.text : AT(ADDR(.text) - PAGE_OFFSET) {
_stext = .;
*(.text .text.*)
_etext = .;
} = 0
. = ALIGN(4096);
/* ===== .rodata: Read-Only Data ===== */
.rodata : AT(ADDR(.rodata) - PAGE_OFFSET) {
_srodata = .;
*(.rodata .rodata.*)
/* C++ global constructor table (.init_array) */
. = ALIGN(8);
__init_array_start = .;
KEEP(*(.init_array .init_array.*))
__init_array_end = .;
_erodata = .;
}
. = ALIGN(4096);
/* ===== .data: Initialized Read-Write Data ===== */
.data : AT(ADDR(.data) - PAGE_OFFSET) {
_sdata = .;
*(.data .data.*)
/* GP anchor: RISC-V medany model uses gp-relative addressing
* for .sdata/.sbss within +/- 2KB of __global_pointer$ */
. = ALIGN(16);
PROVIDE(__global_pointer$ = . + 0x800);
*(.sdata .sdata.*)
_edata = .;
}
. = ALIGN(4096);
/* ===== .bss: Uninitialized Data (zeroed by entry.S) ===== */
.bss : AT(ADDR(.bss) - PAGE_OFFSET) {
_sbss = .;
*(.bss .bss.*)
*(.sbss .sbss.*)
/* Early page table: 4KB aligned, used by entry.S before VMM */
. = ALIGN(4096);
early_pgdir = .;
. += 4096;
/* Per-CPU boot stacks: 8KB per CPU, max 8 CPUs */
. = ALIGN(4096);
boot_stack = .;
. += 8192 * 8; /* NCPU_MAX = 8, BOOT_STACK_SIZE = 8KB */
boot_stack_top = .;
_ebss = .;
}
. = ALIGN(4096);
/* ===== End of kernel image ===== */
_kernel_end = .;
/* Discard unwanted sections */
/DISCARD/ : {
*(.eh_frame .eh_frame_hdr)
*(.note .note.*)
*(.comment)
}
}
|