A Linux module is built with -mcmodel=kernel and can only reach addresses in the top 2 GB, where this kernel is not linked. So the kernel image is mapped a second time at LDLS_KALIAS, with a vmemmap area and a module area beside it, in one PDPT shared by every address space. Nothing loads a module yet; this is the address-space groundwork, set up at every boot, and include/ldls/ is the interface the loader will use. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
123 lines
5.3 KiB
C
123 lines
5.3 KiB
C
#pragma once
|
|
|
|
// Memory layout
|
|
|
|
#define EXTMEM 0x100000 // Start of extended memory
|
|
// Top of usable physical memory. A *variable*, read from the firmware's E820
|
|
// map at boot -- see kernel/arch/x86_64/e820.c. It used to be the constant
|
|
// below, which was not a limit on what the kernel used but an assertion that
|
|
// exactly 224 MB existed: less and the allocator walked off the end of RAM,
|
|
// more and it was invisible.
|
|
//
|
|
// The macro spelling is kept so that the twenty-odd call sites read the same as
|
|
// they always did. It must not be used before e820_init(), which runs first
|
|
// thing in main() for that reason.
|
|
#ifndef __ASSEMBLER__
|
|
extern uint64 phystop;
|
|
#define PHYSTOP phystop
|
|
#endif
|
|
|
|
// PHYSTOP alone describes memory as one run ending at a top address, which is
|
|
// what a BIOS map usually looks like and what UEFI never does: OVMF drops an
|
|
// ACPI NVS region at 0x800000, so the run containing the kernel ends at 8 MB
|
|
// and everything above the hole was invisible. The usable regions are
|
|
// therefore kept as a list as well, and kinit1() frees each one rather than
|
|
// walking a single range from the kernel's end to the top.
|
|
//
|
|
// PHYSTOP still means what it always did -- the top of what kalloc may hand
|
|
// out, and the bound kfree() rejects pages above -- so every existing call
|
|
// site is unaffected.
|
|
#define MEMREGION_MAX 64
|
|
|
|
#ifndef __ASSEMBLER__
|
|
struct memregion {
|
|
uint64 base; // first byte, page aligned
|
|
uint64 end; // one past the last byte, page aligned
|
|
};
|
|
|
|
extern struct memregion mem_usable[MEMREGION_MAX];
|
|
extern int nmem_usable;
|
|
|
|
// The top of the low region: where the DMA arena is carved from, and the
|
|
// ceiling for kinit1(). Always below DIRECTMAP_BOOT, and separate from
|
|
// `phystop` because a device is not obliged to be able to reach the top of
|
|
// memory -- an RTL8139's buffer address register is thirty-two bits wide.
|
|
extern uint64 lowtop;
|
|
#endif
|
|
|
|
// What to assume when the firmware gives us nothing usable: the old constant,
|
|
// so that path behaves exactly as the kernel always did.
|
|
#define PHYSTOP_FALLBACK 0xE000000ULL
|
|
|
|
// The most RAM the kernel will use.
|
|
//
|
|
// This was 0xC0000000 -- three gigabytes -- because kvmalloc() mapped exactly
|
|
// four 1 GB pages and the fourth was marked uncached for the PCI hole. On a
|
|
// laptop with sixteen gigabytes that threw away thirteen of them, silently.
|
|
//
|
|
// kvmalloc() now maps as many 1 GB pages as the machine has RAM, so the limit
|
|
// is the page table rather than a constant: the kernel PDPT has 512 entries
|
|
// and ioremap takes what the direct map does not, so 256 GB of RAM still
|
|
// leaves 248 GB of device window. A machine with more than this gets the rest
|
|
// ignored, with a line saying so.
|
|
//
|
|
// It was 64 GB while handing memory to the allocator meant writing every page
|
|
// of it at boot. kalloc.c keeps never-used memory as ranges now, so a bigger
|
|
// machine costs nothing until its memory is used.
|
|
#define PHYSTOP_MAX (256ULL << 30)
|
|
|
|
// What the *loader's* page tables cover, and therefore the ceiling on anything
|
|
// that runs before kvmalloc() builds the kernel's own.
|
|
//
|
|
// kinit1() frees pages by writing a free-list pointer into each one, so every
|
|
// page it touches has to be mapped at the time. Before kvmalloc that means the
|
|
// low four gigabytes and nothing else, which is why freeing memory happens in
|
|
// two passes -- see kinit_high().
|
|
#define DIRECTMAP_BOOT (4ULL << 30)
|
|
|
|
// Below this the kernel image, its page tables and the DMA arena do not fit.
|
|
#define PHYSTOP_MIN (24ULL * 1024 * 1024)
|
|
|
|
// Key addresses for address space layout
|
|
#define KERNBASE 0xFFFF800000000000 // First kernel virtual address
|
|
// Where the kernel is placed in physical memory, and linked above KERNBASE.
|
|
//
|
|
// 16 MB, not the 1 MB xv6 used. The kernel is 34 MB with the RAM disk in it,
|
|
// and from 1 MB that ran across 8 MB, where OVMF keeps ACPI NVS memory --
|
|
// which outlives the firmware, so the kernel was copied over it after
|
|
// ExitBootServices on every boot. Firmware keeps its leftovers low; above
|
|
// 16 MB is where a machine is most reliably empty. kernel/kernel.ld repeats
|
|
// this number and has to agree.
|
|
#define KERNPHYS 0x1000000
|
|
#define KERNLINK (KERNBASE+KERNPHYS) // Address where kernel is linked
|
|
|
|
// The LDLS window, in the top 2 GB, where a Linux module expects to live. See
|
|
// ldls_vm_init() in kernel/arch/x86_64/vm.c.
|
|
//
|
|
// LDLS_VMEMMAP 1 GB Linux's `struct page` array, 64 bytes per frame --
|
|
// enough for 64 GB, not for all of PHYSTOP_MAX; a
|
|
// frame above that has no struct page. Backed on demand.
|
|
// LDLS_KALIAS 512 MB the kernel image again, from physical zero
|
|
// LDLS_MODBASE 512 MB modules, their stacks and their vmalloc
|
|
#define LDLS_VMEMMAP 0xFFFFFFFF40000000ULL
|
|
#define LDLS_KALIAS 0xFFFFFFFF80000000ULL
|
|
#define LDLS_MODBASE 0xFFFFFFFFA0000000ULL
|
|
#define LDLS_MODEND 0xFFFFFFFFC0000000ULL
|
|
|
|
// A kernel address, as a module sees it.
|
|
#define LDLS_ALIAS(a) ((uint64)(a) - KERNBASE + LDLS_KALIAS)
|
|
|
|
#ifndef __ASSEMBLER__
|
|
static inline addr_t v2p(void *a) {
|
|
return ((addr_t)(a)) - ((addr_t)KERNBASE);
|
|
}
|
|
static inline void *p2v(addr_t a) {
|
|
return (void *)((a) + ((addr_t)KERNBASE));
|
|
}
|
|
#endif
|
|
|
|
#define V2P(a) (((addr_t) (a)) - KERNBASE)
|
|
#define P2V(a) (((void *) (a)) + KERNBASE)
|
|
|
|
#define V2P_WO(x) ((x) - KERNBASE) // same as V2P, but without casts
|
|
#define P2V_WO(x) ((x) + KERNBASE) // same as P2V, but without casts
|