Skip to content

Commit 21a042c

Browse files
committed
arch: give the linear-map base one axis
PAGE_OFFSET was described by seven overlapping macros, and the one question that matters to a component -- can THIS binary know the target's base? -- was asked by none of them. DIRECTMAP_STATIC answers whether the base moves at runtime, a property of the target kernel; a base can be perfectly static there and still unknown here, which is the whole x86_32 / arm32 VMSPLIT case. PAGE_OFFSET_CANDIDATES now states the set an architecture admits, with PAGE_OFFSET_MIN / _MAX bracketing it and PAGE_OFFSET_KNOWN_AT_BUILD derived from the two. VMSPLIT_PAGE_OFFSETS and HAVE_VMSPLIT_PAGE_OFFSET are retired; vmsplit_text_base reads the one list and its gate resolves to the same architecture as before. The window is stated explicitly rather than reusing KERNEL_VIRT_VAS_START, which had quietly acquired the job of naming the lowest split. It is not that quantity: mips64 starts the kernel address space at 0x8000000000000000 with a PAGE_OFFSET of 0xffffffff80000000, and loongarch64 and riscv64 are the same shape. Reading it as the lowest split is right only on the arches that happen to use it that way, this one included as of the module-band change. No list on arm64 or riscv64. Their base is arm64_page_offset_for(va_bits), a function of Q_VA_BITS, which is already a finite set -- a second list would be two declarations obliged to agree, and riscv64's would have to track kernel version as well, since SV39 alone has had two bases. The coupling rule stays the single source of truth. MIN / _MAX must be literals (they appear in #if arithmetic and static initialisers, where an array cannot be indexed), so compile time can only check that they bracket PAGE_OFFSET. The rest is a test that runs per-arch under test-cross: the window is exactly the set's extremes, the compile-time default is admissible, the list is descending and duplicate-free, and one candidate is what KNOWN_AT_BUILD means. Declarations only -- no behaviour change.
1 parent 471b8b4 commit 21a042c

16 files changed

Lines changed: 185 additions & 8 deletions

File tree

src/include/kasld/api.h

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,63 @@ __extension__ _Static_assert((unsigned long)KERNEL_PHYS_MAX >
269269
#error "arch header must define TEXT_TRACKS_DIRECTMAP (0 or 1)"
270270
#endif
271271

272+
/* ---- The linear-map base, as one axis ----------------------------------
273+
*
274+
* PAGE_OFFSET_MIN / PAGE_OFFSET_MAX bracket every linear-map base the
275+
* architecture admits. Required of every arch, and stated as literals rather
276+
* than derived: they appear in #if arithmetic and in static initialisers,
277+
* where a candidate array cannot be indexed.
278+
*
279+
* They exist because KERNEL_VIRT_VAS_START had quietly acquired this second
280+
* job, and it is not the same quantity. On mips64, loongarch64 and riscv64 the
281+
* kernel address space STARTS far below the linear map — VAS_START
282+
* 0x8000000000000000 against a PAGE_OFFSET of 0xffffffff80000000 on mips64 —
283+
* so reading it as "the lowest split" is wrong there, and right elsewhere only
284+
* by coincidence of which arches use it.
285+
*
286+
* PAGE_OFFSET_CANDIDATES is the complete set, highest first, declared ONLY
287+
* where the base is a PRIMITIVE property of the build: a VMSPLIT choice, or an
288+
* architectural constant. Deliberately absent where it is
289+
*
290+
* DERIVED — arm64 and riscv64 compute it from the paging mode, which
291+
* Q_VA_BITS already models as a finite set. A second list there would be
292+
* two declarations obliged to agree, and riscv64's would additionally have
293+
* to track kernel version (SV39 alone has had two bases). The coupling
294+
* rule that maps one to the other is the single source of truth instead.
295+
*
296+
* CONTINUOUS — x86_64 randomizes it (RANDOMIZE_MEMORY) and s390 shifts it;
297+
* there is no set to enumerate.
298+
*
299+
* PAGE_OFFSET_KNOWN_AT_BUILD answers the question none of the older axes did:
300+
* can the ANALYSING BINARY know the target's linear-map base? That is distinct
301+
* from DIRECTMAP_STATIC, which asks whether the base moves at RUNTIME — a
302+
* property of the target kernel. A base can be perfectly static there and
303+
* still unknown here, which is exactly the x86_32 / arm32 VMSPLIT case. */
304+
#ifndef PAGE_OFFSET_MIN
305+
#error \
306+
"arch header must define PAGE_OFFSET_MIN (lowest admissible linear-map base)"
307+
#endif
308+
#ifndef PAGE_OFFSET_MAX
309+
#error "arch header must define PAGE_OFFSET_MAX (highest admissible base)"
310+
#endif
311+
#if PAGE_OFFSET_MIN > PAGE_OFFSET_MAX
312+
#error "PAGE_OFFSET_MIN is above PAGE_OFFSET_MAX"
313+
#endif
314+
#if PAGE_OFFSET < PAGE_OFFSET_MIN || PAGE_OFFSET > PAGE_OFFSET_MAX
315+
#error "the compile-time PAGE_OFFSET falls outside [PAGE_OFFSET_MIN, _MAX]"
316+
#endif
317+
318+
#ifdef PAGE_OFFSET_CANDIDATES
319+
#define PAGE_OFFSET_IS_FINITE 1
320+
#else
321+
#define PAGE_OFFSET_IS_FINITE 0
322+
#endif
323+
324+
/* One admissible value means this binary knows the target's base. A finite set
325+
* with more than one, or no set at all, means it does not. */
326+
#define PAGE_OFFSET_KNOWN_AT_BUILD \
327+
(PAGE_OFFSET_IS_FINITE && PAGE_OFFSET_MIN == PAGE_OFFSET_MAX)
328+
272329
/* MODULES_RELATIVE_TO_PAGE_OFFSET is opt-in: an arch declares it 1 when its
273330
* module band is defined as a DELTA FROM PAGE_OFFSET rather than at fixed
274331
* addresses. Such an arch supplies MODULES_START_FOR(po) / MODULES_END_FOR(po)

src/include/kasld/arch/arm32.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,12 @@
2626
#define PAGE_OFFSET 0xc0000000ul
2727
// VMSPLIT (CONFIG_PAGE_OFFSET) is a compile-time constant, fixed at boot.
2828
#define PAGE_OFFSET_FROM_CONFIG 1
29+
// Every linear-map base an arm32 kernel can be built with, highest first
30+
// (arch/arm/Kconfig: VMSPLIT_3G / 3G_OPT / 2G / 1G). arm32 has no 2G_OPT.
31+
#define PAGE_OFFSET_CANDIDATES \
32+
{0xc0000000ul, 0xb0000000ul, 0x80000000ul, 0x40000000ul}
33+
#define PAGE_OFFSET_MIN 0x40000000ul
34+
#define PAGE_OFFSET_MAX 0xc0000000ul
2935

3036
// The runtime PAGE_OFFSET is one of the VMSPLIT boundaries (arch/arm/Kconfig:
3137
// VMSPLIT_3G / 3G_OPT / 2G / 1G), listed high→low for snap-down. arm32 has no
@@ -35,9 +41,6 @@
3541
// vmsplit_text_base engine rule. The 0xc0000000 default above is only the
3642
// render fallback when no virtual text address is observed.
3743
// https://elixir.bootlin.com/linux/v6.1.1/source/arch/arm/Kconfig#L1116
38-
#define HAVE_VMSPLIT_PAGE_OFFSET 1
39-
#define VMSPLIT_PAGE_OFFSETS \
40-
{0xc0000000ul, 0xb0000000ul, 0x80000000ul, 0x40000000ul}
4144

4245
// https://elixir.bootlin.com/linux/v6.1.1/source/arch/arm/Kconfig#L276
4346
#define PHYS_OFFSET 0ul

src/include/kasld/arch/arm64.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,12 @@
4444
// https://elixir.bootlin.com/linux/v6.12/source/arch/arm64/include/asm/memory.h#L44
4545
// We assume 52 va bits (broadest, covers all configs):
4646
#define PAGE_OFFSET 0xfff0000000000000ul
47+
48+
// Derived from the paging mode: PAGE_OFFSET is -(1 << VA_BITS), so the
49+
// window spans VA_BITS 52 (lowest base) to 39 (highest). Q_VA_BITS carries
50+
// the finite set; arm64_page_offset_from_va_bits maps one to the other.
51+
#define PAGE_OFFSET_MIN PAGE_OFFSET
52+
#define PAGE_OFFSET_MAX 0xffffff8000000000ul
4753
#define PHYS_OFFSET 0ul
4854

4955
// VA_BITS candidates for Q_VA_BITS (finite-set lattice), smallest first. Each

src/include/kasld/arch/loongarch64.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,11 @@
4141
// Unlocks text_base_coupling_synth (it needs Q_PAGE_OFFSET pinned to
4242
// propagate Q_VIRT_IMAGE_BASE ↔ Q_PHYS_IMAGE_BASE).
4343
#define PAGE_OFFSET_INVARIANT 1
44+
// The DMW1 direct-mapped window base, fixed by the architecture. Above
45+
// KERNEL_VIRT_VAS_START (0x8000000000000000), as on mips64.
46+
#define PAGE_OFFSET_CANDIDATES {0x9000000000000000ul}
47+
#define PAGE_OFFSET_MIN 0x9000000000000000ul
48+
#define PAGE_OFFSET_MAX 0x9000000000000000ul
4449

4550
// XKPRANGE starts at 0x8000000000000000 (hardware direct map windows DMW0/1/2).
4651
// XKVRANGE starts at 0xc000000000000000 (vmalloc, modules, vmemmap).

src/include/kasld/arch/mips32.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,10 @@
2727
#define PAGE_OFFSET 0x80000000ul
2828
// CKSEG0 is fixed by the MIPS32 ISA — virt_page_offset cannot vary at runtime.
2929
#define PAGE_OFFSET_INVARIANT 1
30+
// KSEG0, fixed by the MIPS ISA.
31+
#define PAGE_OFFSET_CANDIDATES {0x80000000ul}
32+
#define PAGE_OFFSET_MIN 0x80000000ul
33+
#define PAGE_OFFSET_MAX 0x80000000ul
3034

3135
// https://elixir.bootlin.com/linux/v6.1.1/source/arch/mips/include/asm/mach-generic/spaces.h#L28
3236
#define PHYS_OFFSET 0ul

src/include/kasld/arch/mips64.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,12 @@
1818
#define PAGE_OFFSET 0xffffffff80000000ul
1919
// CKSEG0 is fixed by the MIPS ISA — virt_page_offset cannot vary at runtime.
2020
#define PAGE_OFFSET_INVARIANT 1
21+
// CKSEG0, fixed by the MIPS ISA. Note this sits far ABOVE
22+
// KERNEL_VIRT_VAS_START (0x8000000000000000) -- the kernel address space
23+
// begins well below the linear map here.
24+
#define PAGE_OFFSET_CANDIDATES {0xffffffff80000000ul}
25+
#define PAGE_OFFSET_MIN 0xffffffff80000000ul
26+
#define PAGE_OFFSET_MAX 0xffffffff80000000ul
2127

2228
// https://elixir.bootlin.com/linux/v6.1.1/source/arch/mips/include/asm/mach-generic/spaces.h#L28
2329
#define PHYS_OFFSET 0ul

src/include/kasld/arch/ppc32.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,13 @@
3131
#define DIRECTMAP_STATIC 1
3232
#define TEXT_TRACKS_DIRECTMAP 1
3333
#define PAGE_OFFSET_INVARIANT 1
34+
// One value in practice. arch/powerpc/Kconfig does expose a prompt for it
35+
// (PAGE_OFFSET_BOOL, under ADVANCED_OPTIONS) and two in-tree 85xx defconfigs
36+
// use it, so this set is narrower than the architecture strictly allows --
37+
// see the PAGE_OFFSET_INVARIANT entry in dev/TODO.md.
38+
#define PAGE_OFFSET_CANDIDATES {0xc0000000ul}
39+
#define PAGE_OFFSET_MIN 0xc0000000ul
40+
#define PAGE_OFFSET_MAX 0xc0000000ul
3441

3542
#define KERNEL_VIRT_VAS_START PAGE_OFFSET
3643
#define KERNEL_VIRT_VAS_END 0xfffffffful

src/include/kasld/arch/ppc64.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,11 @@
2525
// book3s64 linear-mapping base is architecturally fixed (not
2626
// user-configurable).
2727
#define PAGE_OFFSET_INVARIANT 1
28+
// book3s64 linear-mapping base. arch/powerpc/Kconfig declares it under
29+
// `if PPC64` as a hex with no prompt, so it cannot be configured.
30+
#define PAGE_OFFSET_CANDIDATES {0xc000000000000000ul}
31+
#define PAGE_OFFSET_MIN 0xc000000000000000ul
32+
#define PAGE_OFFSET_MAX 0xc000000000000000ul
2833

2934
// https://elixir.bootlin.com/linux/v6.1.1/source/arch/powerpc/include/asm/page.h#L227
3035
#define PHYS_OFFSET 0ul

src/include/kasld/arch/riscv32.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@
2929
#define DIRECTMAP_STATIC 1
3030
#define TEXT_TRACKS_DIRECTMAP 1
3131
#define PAGE_OFFSET_INVARIANT 1
32+
// Hard-coded in arch/riscv/include/asm/page.h for 32-bit MMU builds; riscv
33+
// has no CONFIG_PAGE_OFFSET for rv32, so there is nothing to vary.
34+
#define PAGE_OFFSET_CANDIDATES {0xc0000000ul}
35+
#define PAGE_OFFSET_MIN 0xc0000000ul
36+
#define PAGE_OFFSET_MAX 0xc0000000ul
3237

3338
#define KERNEL_VIRT_VAS_START PAGE_OFFSET
3439
#define KERNEL_VIRT_VAS_END 0xfffffffful

src/include/kasld/arch/riscv64.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,13 @@
4242
// https://elixir.bootlin.com/linux/v6.12/source/arch/riscv/include/asm/page.h
4343
#define PAGE_OFFSET 0xff60000000000000ul
4444

45+
// Derived from the paging mode AND the kernel version: SV57/SV48/SV39 each
46+
// have a base, SV39 has had two across releases, and the pre-v5.10 layout
47+
// adds RISCV_LEGACY_PAGE_OFFSET at the top. Q_VA_BITS carries the mode; no
48+
// second list is declared here for the same reason as arm64.
49+
#define PAGE_OFFSET_MIN 0xff60000000000000ul
50+
#define PAGE_OFFSET_MAX RISCV_LEGACY_PAGE_OFFSET
51+
4552
// Physical RAM base (platform-dependent; 0x80000000 for QEMU virt, SiFive,
4653
// etc.)
4754
#define PHYS_OFFSET 0x80000000ul

0 commit comments

Comments
 (0)