include: one folder per subsystem, and includes that name it

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
This commit is contained in:
Nexoniarz 2026-10-23 15:05:12 +02:00
commit a1c965da1e
267 changed files with 1560 additions and 1440 deletions

View file

@ -1,108 +0,0 @@
#pragma once
#include "types.h"
struct sbuf;
// Asking the kernel a question.
//
// docs/architecture/debugging.md milestone D2. The thing this exists to end is the
// ninety-second loop: add a cprintf, rebuild, boot, read the serial log, and
// learn the answer to exactly the one question you thought of before the
// rebuild.
//
// The interesting part is not the views. It is that a subsystem publishes its
// own state with **one line at the bottom of the file that owns the data**, and
// nothing central has to be edited to add one:
//
// dbg_register("dma", dma_dump, "the DMA arena's free extents");
//
// That is the difference between something that stays current and something
// that does not. /proc/sysrq is the version that does not -- a switch in one
// file with a letter per action, which is why after two years it holds three
// self-tests and no state at all.
//
// Views run in ordinary process context, from a write to /dev/dbg or from
// sysrq, so they may take locks. **They must not be called from panic().**
// The argument is whatever followed the view's name on the command line, or
// "" when there was none. Most views ignore it; the ones that can produce a
// hundred lines use it to narrow -- `vma 4` rather than `vma`. It is also the
// shape milestone D3 needs, since `whose <addr>` is nothing but an argument.
typedef void (*dbg_view_fn)(struct sbuf *out, const char *arg);
// Publish a view. `what` is one line, shown by `help`.
//
// Safe to call from any subsystem's init, in any order: the table is static
// and needs no initialisation of its own.
void dbg_register(const char *name, dbg_view_fn fn, const char *what);
// The same, for a view that **changes something**.
//
// Nearly every view only reads, and the few that do not are worth separating
// because of where this can now be reached from. `watch 0xffff...` arms a debug
// register; that is a legitimate thing for a debugger to do and an illegitimate
// thing for a stranger on a TCP socket to do, and milestone D5 put a TCP socket
// in front of it.
//
// The flag lives on the registration and not in a list somewhere, for the same
// reason the registration exists at all: a central list of which views are
// dangerous is a list that goes stale, and it goes stale in the direction where
// a new view is quietly treated as safe.
void dbg_register_rw(const char *name, dbg_view_fn fn, const char *what);
// Answer only the views that read.
//
// `/dev/dbgro` is the same device on minor 1. The minor is the one piece of
// per-open state a character device already sees, so *which node you opened* is
// the permission -- there is nothing to latch, nothing to remember between the
// write and the read, and no way to escalate from one descriptor to the other.
//
// `schdbgd` opens that one and never the other, so nothing reachable over the
// network can arm a watchpoint. See cmd/schdbgd.
int dbg_command_ro(const char *line, struct sbuf *out, int ro);
// --- whose <addr> -----------------------------------------------------------
//
// The query the views cannot answer between them: *who owns this page?*
//
// Each view speaks for one subsystem, which is what keeps them cheap and
// current -- and it is exactly why none of them can see the bug that matters.
// A page on the DMA arena's free list looks fine from dma.c. The same page on
// kalloc's free list looks fine from kalloc.c. That it is on both is a fact no
// single subsystem holds, and it is the bug that cost this project a day.
//
// So `whose` asks every subsystem about one page and counts the answers. The
// contributors are registered the same way views are, for the same reason:
// adding one is a line in the file that owns the data.
struct whose {
uint64 phys; // the page being asked about, page-aligned
uint64 off; // how far into it the original address was
int owners; // allocators and reserved regions claiming it
int free_owners; // of those, how many believe it is unused
int mappings; // user page tables mapping it
};
typedef void (*dbg_whose_fn)(struct sbuf *out, struct whose *w);
// Publish a claimant. `name` is the column it prints under.
void dbg_register_whose(const char *name, dbg_whose_fn fn);
// Run one command line and render the answer. Returns the number of bytes
// written into `out`.
//
// The protocol is lines of text -- see docs/architecture/debugging.md for why that and
// not a typed binary format. Commands:
//
// help what this kernel can be asked
// all every view, in registration order
// <name> [arg] that view, optionally narrowed
// whose <addr> every subsystem's claim on one page
int dbg_command(const char *line, struct sbuf *out);
// Every view, straight to the console. This is what sysrq 'g' runs, and it is
// the level-0 path from the plan: no process, no filesystem, no client.
void dbg_dump_all(void);
#define DBG_MAJOR 10