Nexoniarz is the sole author and SchOS was never published under Apache-2.0, so this is a straight relicence. LICENSE is the FSF GPLv2 text, every first-party SPDX header moves to GPL-2.0-or-later, and NOTICE, README.md, docs/licensing.md and the site say so. projects/schfs-linux follows the rest of the tree. The GPL gives copyleft: a fork has to ship its source. It also lifts the old "Linux drivers, never" rule, since GPL-2.0-only code combines with GPL-2.0-or-later. "Or later" leaves room for GPLv3, but one binary still has to pick one version, so docs/licensing.md now keeps Apache-2.0 and GPLv3 code out of the kernel to keep Linux code possible there. BSD 4-clause code goes from "avoid" to "no", because the advertising clause is GPL-incompatible. LDLS still ships no .ko. That boundary is now project policy rather than a legal requirement, and ldls.md, devices.md and licensing.md section 6 say so. refmod declares license=GPL, and ldls-check passes (27 checks). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
96 lines
2.7 KiB
C
96 lines
2.7 KiB
C
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
//
|
|
// Register access. See ldls/kpi/kpi.h for the provenance rule.
|
|
//
|
|
// These are the busiest symbols by a wide margin -- 538 of 8139too's 552 probe
|
|
// calls are two of them -- and they are also the shortest, because once a BAR
|
|
// is mapped a register access *is* a memory access. The whole of what these
|
|
// add over a plain dereference is the `volatile`, which stops a compiler
|
|
// deciding that reading the same address twice is redundant. For a status
|
|
// register, reading it twice is the entire point.
|
|
//
|
|
// The argument order is worth noting because it is the opposite of what a C
|
|
// programmer expects and getting it backwards produces something that almost
|
|
// works: Linux's writes take the **value first** and the address second.
|
|
|
|
#include "types.h"
|
|
#include "kpi.h"
|
|
|
|
// Every access is checked against the mapping `pci_iomap` returned.
|
|
//
|
|
// A driver that reaches outside its own BAR would otherwise take the process
|
|
// down with a page fault, and the report would be an address with no context.
|
|
// This turns that into a line naming the offset it wanted -- and since there
|
|
// is no IOMMU, a hosted driver's stray accesses are exactly the class of thing
|
|
// that has to be noticed early or not at all.
|
|
int
|
|
kpi_io_ok(void *addr, int width, int write)
|
|
{
|
|
unsigned long a = (unsigned long)addr;
|
|
|
|
if (kpi.io_base && a >= kpi.io_base &&
|
|
a + (unsigned long)width <= kpi.io_base + kpi.io_len)
|
|
return 1;
|
|
|
|
kpi.io_stray++;
|
|
if (kpi.io_stray <= 8) {
|
|
kpi_log(" kpi: the driver tried to ");
|
|
kpi_log(write ? "write " : "read ");
|
|
kpi_lognum(width);
|
|
kpi_log(" byte(s) at 0x");
|
|
kpi_loghex(a, 16);
|
|
if (kpi.io_base && a < kpi.io_base) {
|
|
kpi_log(", which is ");
|
|
kpi_lognum((long long)(kpi.io_base - a));
|
|
kpi_log(" below the mapping");
|
|
} else if (kpi.io_base) {
|
|
kpi_log(", which is past the end of the mapping");
|
|
} else {
|
|
kpi_log(", but nothing is mapped yet");
|
|
}
|
|
kpi_log("\n");
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
unsigned char
|
|
kpi_ioread8(void *addr)
|
|
{
|
|
if (!kpi_io_ok(addr, 1, 0)) return 0xff;
|
|
return *(volatile unsigned char *)addr;
|
|
}
|
|
|
|
unsigned short
|
|
kpi_ioread16(void *addr)
|
|
{
|
|
if (!kpi_io_ok(addr, 2, 0)) return 0xffff;
|
|
return *(volatile unsigned short *)addr;
|
|
}
|
|
|
|
unsigned int
|
|
kpi_ioread32(void *addr)
|
|
{
|
|
if (!kpi_io_ok(addr, 4, 0)) return 0xffffffff;
|
|
return *(volatile unsigned int *)addr;
|
|
}
|
|
|
|
void
|
|
kpi_iowrite8(unsigned char v, void *addr)
|
|
{
|
|
if (!kpi_io_ok(addr, 1, 1)) return;
|
|
*(volatile unsigned char *)addr = v;
|
|
}
|
|
|
|
void
|
|
kpi_iowrite16(unsigned short v, void *addr)
|
|
{
|
|
if (!kpi_io_ok(addr, 2, 1)) return;
|
|
*(volatile unsigned short *)addr = v;
|
|
}
|
|
|
|
void
|
|
kpi_iowrite32(unsigned int v, void *addr)
|
|
{
|
|
if (!kpi_io_ok(addr, 4, 1)) return;
|
|
*(volatile unsigned int *)addr = v;
|
|
}
|