Sixty-five headers sat side by side in include/, so `#include "irq.h"` said nothing about where irq.h was or what it belonged to, and errno.h, stat.h and fcntl.h at the top shadowed the system's for any host tool built with -I./include. They are in folders now -- arch/ core/ fs/ dev/ gfx/ net/ uapi/ (and ldls/ for the Linux driver layer) -- and every include names the folder, as Linux's do: "core/proc.h". Done mechanically and checked the hard way: the kernel built from this tree disassembles identically to the one built from the tree before it. The full image boots, and userland is the same set of programs. Paths in docs and comments follow; docs/guides/layout.md has a table of what is where, and tools/fix-includes.py rewrites old-style includes from the folders in the tree, for code written before this. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
268 lines
10 KiB
C
268 lines
10 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
#pragma once
|
|
|
|
// Loading a relocatable object. docs/architecture/ldls.md, "The loader".
|
|
//
|
|
// A Linux `.ko` is an ordinary ELF64 relocatable object -- the same thing
|
|
// `gcc -c` produces -- and loading one is four steps with no mystery in any of
|
|
// them: index the sections, place the allocatable ones, resolve the undefined
|
|
// symbols against a table, and apply the relocations. There is no licence
|
|
// question anywhere in this file: ELF and the x86-64 relocation set are
|
|
// published specifications, which is the case [../docs/licensing.md] §5
|
|
// describes.
|
|
//
|
|
// **It is freestanding on purpose.** No libc, no allocation, no I/O: the
|
|
// caller hands over the whole image and a buffer, and everything happens in
|
|
// them. That is what lets the same source build as a host tool -- where a test
|
|
// takes a second -- and as the SchOS-side host, which is the discipline
|
|
// `mkschfs` and the kernel already share and the reason SchFS format bugs are
|
|
// found on the host.
|
|
//
|
|
// Types are spelled out rather than taken from a header, because the two sides
|
|
// have different ones and this file has to mean the same thing in both.
|
|
|
|
// The section table is the caller's, not ours.
|
|
//
|
|
// A fixed array needs a limit, and every limit that would fit in a struct is
|
|
// one a real object exceeds: measured over 300 modules the median is 50
|
|
// sections and the 95th percentile is 67, but an object built with
|
|
// -ffunction-sections runs to thousands -- nvidia-modeset has 7,069. Rather
|
|
// than pick a number that is generous until it is not, the caller says how
|
|
// many it is prepared for, and ko_sections_needed() says how many that is.
|
|
//
|
|
// A suggested size for a fixed table on the SchOS side, where allocating is
|
|
// less convenient. It is a caller's choice and not the loader's limit.
|
|
#define KO_SECHINT 128
|
|
|
|
// Undefined symbols the report will hold. Measured over the same corpus the
|
|
// median is 25 and the worst seen is 245, so this is room to spare -- and
|
|
// `undef_lost` says so rather than the list quietly ending.
|
|
#define KO_MAXUNDEF 512
|
|
|
|
// --- ELF64, the relocatable subset ------------------------------------------
|
|
//
|
|
// include/core/elf.h has `elfhdr` and `proghdr`, which are the ET_EXEC half. None of
|
|
// what a relocatable object needs is there, so it is here.
|
|
|
|
struct ko_ehdr {
|
|
unsigned char e_ident[16];
|
|
unsigned short e_type;
|
|
unsigned short e_machine;
|
|
unsigned int e_version;
|
|
unsigned long long e_entry;
|
|
unsigned long long e_phoff;
|
|
unsigned long long e_shoff;
|
|
unsigned int e_flags;
|
|
unsigned short e_ehsize;
|
|
unsigned short e_phentsize;
|
|
unsigned short e_phnum;
|
|
unsigned short e_shentsize;
|
|
unsigned short e_shnum;
|
|
unsigned short e_shstrndx;
|
|
};
|
|
|
|
struct ko_shdr {
|
|
unsigned int sh_name;
|
|
unsigned int sh_type;
|
|
unsigned long long sh_flags;
|
|
unsigned long long sh_addr;
|
|
unsigned long long sh_offset;
|
|
unsigned long long sh_size;
|
|
unsigned int sh_link;
|
|
unsigned int sh_info;
|
|
unsigned long long sh_addralign;
|
|
unsigned long long sh_entsize;
|
|
};
|
|
|
|
struct ko_sym {
|
|
unsigned int st_name;
|
|
unsigned char st_info;
|
|
unsigned char st_other;
|
|
unsigned short st_shndx;
|
|
unsigned long long st_value;
|
|
unsigned long long st_size;
|
|
};
|
|
|
|
struct ko_rela {
|
|
unsigned long long r_offset;
|
|
unsigned long long r_info;
|
|
long long r_addend;
|
|
};
|
|
|
|
#define KO_ET_REL 1
|
|
#define KO_EM_X86_64 62
|
|
|
|
#define KO_SHT_PROGBITS 1
|
|
#define KO_SHT_SYMTAB 2
|
|
#define KO_SHT_STRTAB 3
|
|
#define KO_SHT_RELA 4
|
|
#define KO_SHT_NOBITS 8
|
|
|
|
#define KO_SHF_WRITE 0x1
|
|
#define KO_SHF_ALLOC 0x2
|
|
#define KO_SHF_EXECINSTR 0x4
|
|
|
|
#define KO_SHN_UNDEF 0
|
|
#define KO_SHN_ABS 0xfff1
|
|
#define KO_SHN_COMMON 0xfff2
|
|
|
|
#define KO_R_SYM(i) ((unsigned int)((i) >> 32))
|
|
#define KO_R_TYPE(i) ((unsigned int)((i) & 0xffffffffu))
|
|
|
|
// The x86-64 relocations a compiled object actually contains. Anything else is
|
|
// refused by name rather than ignored -- a relocation silently skipped is a
|
|
// wrong address found much later.
|
|
#define KO_R_X86_64_NONE 0
|
|
#define KO_R_X86_64_64 1
|
|
#define KO_R_X86_64_PC32 2
|
|
#define KO_R_X86_64_PLT32 4
|
|
#define KO_R_X86_64_32 10
|
|
#define KO_R_X86_64_32S 11
|
|
#define KO_R_X86_64_PC64 24
|
|
|
|
// --- what the loader knows about a section ----------------------------------
|
|
|
|
struct ko_section {
|
|
const char *name;
|
|
unsigned int type;
|
|
unsigned long long flags;
|
|
unsigned long long size;
|
|
unsigned long long align;
|
|
const unsigned char *data; // 0 for NOBITS
|
|
int alloc; // takes space at run time
|
|
unsigned long long addr; // where it will run, once laid out
|
|
unsigned char *where; // where it is right now, once laid out
|
|
};
|
|
|
|
// Resolving a name to an address. Returns 0 and fills `out` on success, or
|
|
// non-zero to say it does not know it -- which is not an error at L0, it is
|
|
// the answer we are asking for.
|
|
typedef int (*ko_resolver)(void *ctx, const char *name,
|
|
unsigned long long *out);
|
|
|
|
struct ko {
|
|
const unsigned char *img;
|
|
unsigned long long len;
|
|
|
|
const struct ko_ehdr *eh;
|
|
const unsigned char *shtab; // raw, indexed with e_shentsize
|
|
int nsh;
|
|
|
|
const char *shstr; // section name strings
|
|
const struct ko_sym *sym;
|
|
int nsym;
|
|
const char *str; // symbol name strings
|
|
|
|
struct ko_section *sec; // the caller's, nsh entries used
|
|
|
|
const char *undef[KO_MAXUNDEF];
|
|
int nundef;
|
|
int undef_lost; // more than KO_MAXUNDEF of them
|
|
|
|
unsigned long long span; // bytes ko_layout needs
|
|
int laid_out;
|
|
|
|
// How many relocations of each type the object contains, counted by
|
|
// ko_reltypes(). The question "what does the loader actually have to
|
|
// handle" has an exact answer per module, and guessing at it is how a
|
|
// loader ends up refusing a driver on its last relocation.
|
|
unsigned int reltype[64];
|
|
unsigned int reltype_other;
|
|
unsigned int nrel;
|
|
|
|
char err[128];
|
|
};
|
|
|
|
// How many `struct ko_section` this object needs. -1 if it is not an ELF64
|
|
// object at all, which is worth knowing before allocating anything for it.
|
|
int ko_sections_needed(const void *image, unsigned long long len);
|
|
|
|
// Validate and index, using `sec` for the section table. Returns 0, or -1 with
|
|
// ko_err() set -- including when `nsec` is too small, which says how many were
|
|
// needed rather than just refusing.
|
|
int ko_open(struct ko *k, const void *image, unsigned long long len,
|
|
struct ko_section *sec, int nsec);
|
|
|
|
// Bytes ko_layout will need. Valid after ko_open.
|
|
unsigned long long ko_span(const struct ko *k);
|
|
|
|
// Place every allocatable section into `mem`, as if it will run at `base`.
|
|
// The two differ when the object is staged somewhere before being mapped;
|
|
// pass base == (address of mem) when they do not.
|
|
int ko_layout(struct ko *k, void *mem, unsigned long long cap,
|
|
unsigned long long base);
|
|
|
|
// Count the relocations by type, without applying any. Valid after ko_open.
|
|
void ko_reltypes(struct ko *k);
|
|
|
|
// Apply every relocation. Undefined symbols go to `r`; a name it does not know
|
|
// makes this fail, naming the first one.
|
|
int ko_relocate(struct ko *k, ko_resolver r, void *ctx);
|
|
|
|
// Neutralise every `%gs:`-relative load of a named symbol.
|
|
//
|
|
// Linux builds modules with `-mstack-protector-guard-reg=gs`, so the stack
|
|
// canary is fetched through the GS segment:
|
|
//
|
|
// mov %gs:__ref_stack_chk_guard(%rip), %rax (prologue)
|
|
// sub %gs:__ref_stack_chk_guard(%rip), %rax (epilogue, then jne)
|
|
//
|
|
// That is an ABI between the kernel and its own per-CPU area, and a host which
|
|
// is not that kernel cannot provide it. On SchOS the GS base belongs to the
|
|
// kernel, so a user-mode read of it faults on a kernel address -- which is
|
|
// exactly where 8139too's probe stopped the first time it ran there.
|
|
//
|
|
// So the instruction is rewritten to zero the destination register. The canary
|
|
// becomes zero, the check at the end of the function compares zero against
|
|
// zero, and `__stack_chk_fail` is never reached. What is lost is a hardening
|
|
// measure that was never going to work here; what is gained is a driver that
|
|
// runs.
|
|
//
|
|
// Call it **after** ko_relocate(), which will have written a displacement into
|
|
// bytes this then overwrites entirely. Returns how many it patched, or -1 if
|
|
// it found something at that offset it did not recognise -- in which case
|
|
// nothing is modified, because a loader that half-understands an instruction
|
|
// should not be editing it.
|
|
int ko_defuse_gs(struct ko *k, const char *sym);
|
|
|
|
// Turn every *other* `%gs:`-relative reference into an ordinary one.
|
|
//
|
|
// The stack guard is one per-CPU variable; there are others, and `current` is
|
|
// the one every driver touches. `mov %gs:const_current_task(%rip), %r8` reads
|
|
// a pointer out of the kernel's per-CPU area, and a host that is not that
|
|
// kernel has no such area -- so on SchOS it reads a kernel address from user
|
|
// mode and faults.
|
|
//
|
|
// Defusing is not available here: the guard's *value* is arbitrary, so zeroing
|
|
// a register is a correct answer, and `current`'s is not -- the driver will
|
|
// dereference it.
|
|
//
|
|
// What works instead is that **a per-CPU variable in a single-threaded host is
|
|
// just a variable**. Taking the `%gs` off leaves the same instruction reading
|
|
// the same width in the same direction, from storage the embedder supplies for
|
|
// that name. Eight bytes become seven and a nop, and the driver never learns
|
|
// the difference.
|
|
//
|
|
// `percpu` is asked for an address for each name and should return the same
|
|
// one every time it is asked for that name -- and should initialise it, since
|
|
// the driver now reads its *contents*: zero is right for a counter and wrong
|
|
// for `current`. Returning 0 refuses the object.
|
|
//
|
|
// Call after ko_relocate() and after ko_defuse_gs(), for the same reason.
|
|
// Returns how many it rewrote, or -1.
|
|
int ko_fixup_percpu(struct ko *k,
|
|
unsigned long long (*percpu)(void *ctx, const char *name),
|
|
void *ctx);
|
|
|
|
// A value from the `.modinfo` section -- "license", "description", "author",
|
|
// "alias". Returns 0 if the object has no such key.
|
|
//
|
|
// Worth having at L0 rather than later: the first thing anyone should be able
|
|
// to ask about a module is what licence it declares, and that is a string in
|
|
// the file rather than anything that needs loading.
|
|
const char *ko_modinfo(const struct ko *k, const char *key);
|
|
|
|
// The module's own name, from `.gnu.linkonce.this_module`, or 0.
|
|
const char *ko_name(const struct ko *k);
|
|
|
|
const char *ko_err(const struct ko *k);
|