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:
parent
0e39e711f1
commit
a1c965da1e
267 changed files with 1560 additions and 1440 deletions
61
include/arch/ioperm.h
Normal file
61
include/arch/ioperm.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
// Port I/O, from a process.
|
||||
//
|
||||
// A Linux driver does not always ask. `ioread32` is a function call LDLS can
|
||||
// implement, but `outl` is an *instruction*, compiled into the module, and the
|
||||
// first foreign driver to need one found this the hard way:
|
||||
//
|
||||
// e1000_io_write+0xd: out %eax,(%dx) -> trap 13 err 0, rdx=0xc000
|
||||
//
|
||||
// That is not a driver doing something exotic. e1000's own reset path picks it
|
||||
// deliberately -- "these controllers can't ack the 64-bit write when issuing
|
||||
// the reset, so use IO-mapping as a workaround" -- so on QEMU's 82540EM there
|
||||
// is no route to a working NIC that avoids it. Any layer that runs somebody
|
||||
// else's drivers has to let a process reach the ports of the device it holds.
|
||||
//
|
||||
// **Which ports, and no others.** x86 offers two ways to grant this and they
|
||||
// are very far apart. IOPL=3 is one flag and hands over all 65536 ports -- the
|
||||
// interrupt controller, the timer, the disk. The TSS I/O permission bitmap is
|
||||
// per port, and the ports a process gets are exactly the I/O BARs of the PCI
|
||||
// devices it has claimed. The second costs a few hundred lines and is the only
|
||||
// one worth having: a foreign driver already has DMA with no IOMMU, and the
|
||||
// answer to "this is not a security boundary" is not to move it further.
|
||||
//
|
||||
// It is the same bargain as kpi_io_ok() in ldls/kpi/io.c, one level down and
|
||||
// enforced by hardware rather than by the driver's host being polite.
|
||||
|
||||
#include "core/types.h"
|
||||
|
||||
struct proc;
|
||||
|
||||
// Ranges per process. A PCI device has at most six BARs and a process may hold
|
||||
// several devices; eight is past anything seen and small enough to scan.
|
||||
#define NIOPORT 8
|
||||
|
||||
struct ioport_range {
|
||||
uint16 base;
|
||||
uint16 len;
|
||||
};
|
||||
|
||||
// Grant / revoke. Called from /dev/pci when a process claims or releases a
|
||||
// device, and from exit() by way of pciuser_release_all().
|
||||
//
|
||||
// Granting a range twice is not an error -- a driver may claim, release and
|
||||
// claim again -- and revoking one that was never granted is not either.
|
||||
void ioperm_grant(struct proc *p, uint16 base, uint16 len);
|
||||
void ioperm_revoke_all(struct proc *p);
|
||||
|
||||
// Install this process's ranges in the running CPU's TSS. Called from
|
||||
// switchuvm() with interrupts off.
|
||||
void ioperm_switch(struct proc *p);
|
||||
|
||||
// The per-CPU TSS, which now has a bitmap attached to it. seginit() asks for
|
||||
// this CPU's and points the GDT descriptor at it.
|
||||
void *ioperm_tss(int cpu, uint64 *limit);
|
||||
|
||||
// The same block, for everyone after seginit().
|
||||
void *ioperm_tss_of(int cpu);
|
||||
|
||||
// Where RSP0 lives, so switchuvm() does not have to know the layout.
|
||||
void ioperm_set_rsp0(void *tss, addr_t stktop);
|
||||
Loading…
Reference in a new issue