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
255
include/arch/x86.h
Normal file
255
include/arch/x86.h
Normal file
|
|
@ -0,0 +1,255 @@
|
|||
#pragma once
|
||||
|
||||
struct dtr {
|
||||
ushort limit;
|
||||
uint64 base;
|
||||
} __attribute__((packed));
|
||||
|
||||
static inline uchar
|
||||
inb(ushort port)
|
||||
{
|
||||
uchar data;
|
||||
asm volatile("in %1,%0" : "=a" (data) : "d" (port));
|
||||
return data;
|
||||
}
|
||||
|
||||
// Cycle counter. Not a clock -- it does not convert to time without knowing the
|
||||
// frequency, and it is not synchronised across cores -- but for "which of these
|
||||
// two paths costs more" it is exactly the right instrument, and the only one
|
||||
// with fine enough resolution to see inside a single syscall.
|
||||
static inline uint64
|
||||
rdtsc(void)
|
||||
{
|
||||
uint lo, hi;
|
||||
asm volatile("rdtsc" : "=a" (lo), "=d" (hi));
|
||||
return ((uint64)hi << 32) | lo;
|
||||
}
|
||||
|
||||
// The x87/MMX/SSE register file, to and from a 512-byte, 16-byte-aligned area.
|
||||
static inline void
|
||||
fxsave(void *area)
|
||||
{
|
||||
asm volatile("fxsave64 (%0)" : : "r"(area) : "memory");
|
||||
}
|
||||
|
||||
static inline void
|
||||
fxrstor(const void *area)
|
||||
{
|
||||
asm volatile("fxrstor64 (%0)" : : "r"(area) : "memory");
|
||||
}
|
||||
|
||||
static inline void
|
||||
insl(int port, void *addr, int cnt)
|
||||
{
|
||||
asm volatile("cld; rep insl" :
|
||||
"=D" (addr), "=c" (cnt) :
|
||||
"d" (port), "0" (addr), "1" (cnt) :
|
||||
"memory", "cc");
|
||||
}
|
||||
|
||||
static inline void
|
||||
outb(ushort port, uchar data)
|
||||
{
|
||||
asm volatile("out %0,%1" : : "a" (data), "d" (port));
|
||||
}
|
||||
|
||||
// 16 bits. Added for AC'97, whose mixer is entirely 16-bit registers: reading
|
||||
// one of them a byte at a time returns the low half twice on some codecs,
|
||||
// because the read of the low byte is what latches the pair.
|
||||
static inline ushort
|
||||
inw(ushort port)
|
||||
{
|
||||
ushort data;
|
||||
asm volatile("inw %1,%0" : "=a" (data) : "d" (port));
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline uint
|
||||
inl(ushort port)
|
||||
{
|
||||
uint data;
|
||||
asm volatile("inl %1,%0" : "=a" (data) : "d" (port));
|
||||
return data;
|
||||
}
|
||||
|
||||
static inline void
|
||||
outw(ushort port, ushort data)
|
||||
{
|
||||
asm volatile("out %0,%1" : : "a" (data), "d" (port));
|
||||
}
|
||||
|
||||
// PCI configuration space is reached through a pair of 32-bit ports, so this
|
||||
// is not optional decoration -- see kernel/dev/pci.c.
|
||||
static inline void
|
||||
outl(ushort port, uint data)
|
||||
{
|
||||
asm volatile("outl %0,%1" : : "a" (data), "d" (port));
|
||||
}
|
||||
|
||||
static inline void
|
||||
outsl(int port, const void *addr, int cnt)
|
||||
{
|
||||
asm volatile("cld; rep outsl" :
|
||||
"=S" (addr), "=c" (cnt) :
|
||||
"d" (port), "0" (addr), "1" (cnt) :
|
||||
"cc");
|
||||
}
|
||||
|
||||
static inline void
|
||||
stosb(void *addr, int data, int cnt)
|
||||
{
|
||||
asm volatile("cld; rep stosb" :
|
||||
"=D" (addr), "=c" (cnt) :
|
||||
"0" (addr), "1" (cnt), "a" (data) :
|
||||
"memory", "cc");
|
||||
}
|
||||
|
||||
// 64-bit-only helpers. `rep stosq` and `xchgq` do not exist in 32-bit mode, so
|
||||
// these must not even be parsed by the -m32 bootloader build -- they compiled
|
||||
// there before only because uint64 was accidentally 32 bits wide, which is the
|
||||
// bug include/core/types.h now asserts against.
|
||||
#ifdef __x86_64__
|
||||
static inline void
|
||||
stosq(void *addr, uint64 data, int cnt)
|
||||
{
|
||||
asm volatile("cld; rep stosq" :
|
||||
"=D" (addr), "=c" (cnt) :
|
||||
"0" (addr), "1" (cnt), "a" (data) :
|
||||
"memory", "cc");
|
||||
}
|
||||
|
||||
struct segdesc;
|
||||
|
||||
static inline void
|
||||
lgdt(struct segdesc *p, int size)
|
||||
{
|
||||
struct dtr d;
|
||||
d.limit = size - 1;
|
||||
d.base = (uint64)p;
|
||||
asm volatile("lgdt (%0)" : : "r" (&d));
|
||||
}
|
||||
|
||||
struct gatedesc;
|
||||
|
||||
static inline void
|
||||
lidt(struct gatedesc *p, int size)
|
||||
{
|
||||
struct dtr d;
|
||||
d.limit = size - 1;
|
||||
d.base = (uint64)p;
|
||||
asm volatile("lidt (%0)" : : "r" (&d));
|
||||
}
|
||||
|
||||
static inline void
|
||||
ltr(ushort sel)
|
||||
{
|
||||
asm volatile("ltr %0" : : "r" (sel));
|
||||
}
|
||||
|
||||
static inline uint64
|
||||
readeflags(void)
|
||||
{
|
||||
uint64 flags;
|
||||
asm volatile("pushfq; pop %0" : "=r" (flags));
|
||||
return flags;
|
||||
}
|
||||
|
||||
static inline void
|
||||
cli(void)
|
||||
{
|
||||
asm volatile("cli");
|
||||
}
|
||||
|
||||
static inline void
|
||||
sti(void)
|
||||
{
|
||||
asm volatile("sti");
|
||||
}
|
||||
|
||||
static inline void
|
||||
hlt(void)
|
||||
{
|
||||
asm volatile("hlt");
|
||||
}
|
||||
|
||||
static inline uint64
|
||||
xchg(volatile uint64 *addr, uint64 newval)
|
||||
{
|
||||
uint64 result;
|
||||
asm volatile("lock; xchgq %0, %1" :
|
||||
"+m" (*addr), "=a" (result) :
|
||||
"1" (newval) :
|
||||
"cc");
|
||||
return result;
|
||||
}
|
||||
#endif /* __x86_64__ */
|
||||
|
||||
static inline uint64
|
||||
rcr2(void)
|
||||
{
|
||||
uint64 val;
|
||||
asm volatile("mov %%cr2,%0" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
static inline void
|
||||
lcr3(uint64 val)
|
||||
{
|
||||
asm volatile("mov %0,%%cr3" : : "r" (val));
|
||||
}
|
||||
|
||||
// Invalidate the TLB entry for one page. Needed any time a PTE is changed
|
||||
// or cleared for an address space that may still be the active CR3 —
|
||||
// otherwise the CPU can keep translating through the stale entry until the
|
||||
// next full CR3 reload (context switch), silently reading/writing the
|
||||
// wrong physical page.
|
||||
static inline void
|
||||
invlpg(void *va)
|
||||
{
|
||||
asm volatile("invlpg (%0)" : : "r" (va) : "memory");
|
||||
}
|
||||
|
||||
static inline void
|
||||
wrmsr(uint32 msr, uint64 val)
|
||||
{
|
||||
uint32 low = (uint32)val;
|
||||
uint32 high = (uint32)(val >> 32);
|
||||
asm volatile("wrmsr" : : "c" (msr), "a" (low), "d" (high));
|
||||
}
|
||||
|
||||
static inline uint64
|
||||
rdmsr(uint32 msr)
|
||||
{
|
||||
uint32 low, high;
|
||||
asm volatile("rdmsr" : "=a" (low), "=d" (high) : "c" (msr));
|
||||
return ((uint64)high << 32) | low;
|
||||
}
|
||||
|
||||
static inline uint64
|
||||
readcs(void)
|
||||
{
|
||||
uint64 val;
|
||||
asm volatile("mov %%cs, %0" : "=r" (val));
|
||||
return val;
|
||||
}
|
||||
|
||||
// CPUID. `leaf` in EAX, results in EAX/EBX/ECX/EDX.
|
||||
//
|
||||
// %rbx is callee-saved *and* the PIC base register on some builds, so it is
|
||||
// exchanged out rather than named as an operand -- naming it directly is the
|
||||
// classic way to get "inline asm clobbers reserved register" or, worse, silent
|
||||
// corruption in the caller.
|
||||
static inline void
|
||||
cpuid_leaf(uint32 leaf, uint32 *a, uint32 *b, uint32 *c, uint32 *d)
|
||||
{
|
||||
uint32 ra, rb, rc, rd;
|
||||
asm volatile("xchgq %%rbx, %q1\n\t"
|
||||
"cpuid\n\t"
|
||||
"xchgq %%rbx, %q1"
|
||||
: "=a"(ra), "=&r"(rb), "=c"(rc), "=d"(rd)
|
||||
: "0"(leaf), "2"(0));
|
||||
if (a) *a = ra;
|
||||
if (b) *b = rb;
|
||||
if (c) *c = rc;
|
||||
if (d) *d = rd;
|
||||
}
|
||||
Loading…
Reference in a new issue