The firmware's AML is now interpreted. uACPI 6.1.1 (MIT) is fetched by ports/uacpi, checksum-verified, and compiled into the kernel unmodified, the same way lwIP is. kernel/acpi/host.c is its host layer: memory, mapping, port and PCI config I/O, time, mutexes and events that spin before the scheduler exists, the SCI, and an "acpi" thread for the work the SCI defers. PCI interrupts go where the board says. pci_init() now routes every device's INTx through the root bridge's _PRT before drivers bind. It follows link devices' _CRS, uses a bridge's own _PRT where the namespace has one, and swizzles through bridges that don't. Before this, INTx waited on the 8259's line number, which is the wrong pin in APIC mode. irq_register() takes a trigger mode rather than a level/low flag, because q35's links and most SCIs are level, active-high. The MADT's interrupt source overrides are now parsed, and are what places the SCI. The power button syncs the filesystems and powers off. shutdown() and reboot() go through the firmware's S5 and reset register first, and only then fall back to the emulators' ports, which a real board does not answer. Tested under QEMU: q35 with MSI off routes xHCI to GSI 22, level/active-high, and it takes real interrupts with nothing polled. system_powerdown powers off q35 and i440fx (QEMU exits 0), and q35 with 4 CPUs boots from NVMe with USB hot-plug working alongside. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
356 lines
16 KiB
Markdown
356 lines
16 KiB
Markdown
# Licensing
|
|
|
|
The one page to check before copying anyone else's code into SchOS.
|
|
|
|
Referenced from `LICENSE`, `LICENSE.MIT` and `NOTICE`, all three of which
|
|
pointed here long before this file existed.
|
|
|
|
---
|
|
|
|
## 1. SchOS is GPL-2.0-or-later
|
|
|
|
Copyright Nexoniarz. See `LICENSE`. Until 2026-10 SchOS was Apache-2.0; it was
|
|
never published under that licence, and as the sole author Nexoniarz relicensed
|
|
it outright.
|
|
|
|
**Why the GPL.** Two reasons, one about others and one about us:
|
|
|
|
- **Copyleft.** Anyone may use, study, modify and redistribute SchOS — but
|
|
whoever ships it, or something built from it, must ship the source of that
|
|
too, under the same terms. Under Apache-2.0 a fork could be closed and sold
|
|
with no changes given back. The GPL does not forbid commercial use; it forbids
|
|
taking the work private.
|
|
- **Linux.** Linux is GPL-2.0-only, and Apache-2.0 could not be combined with
|
|
it. Under the GPL, Linux drivers and code can be adopted (§2).
|
|
|
|
**Why "or later".** It keeps one door open that "only" would close: GPLv3 and
|
|
Apache-2.0 code can still be combined with SchOS code, with that combination
|
|
shipping under GPLv3. See §2 for why the kernel should not walk through it.
|
|
|
|
**What was given up.** Apache-2.0 had an express patent grant; GPLv2 has only
|
|
an implied one. That mattered most for outside contributions, and there are
|
|
none yet.
|
|
|
|
New first-party files carry `SPDX-License-Identifier: GPL-2.0-or-later`.
|
|
|
|
---
|
|
|
|
## 2. What can be copied in
|
|
|
|
| Licence | Verdict | Obligation |
|
|
|---|---|---|
|
|
| Public domain, 0BSD, CC0 | **Yes** | None |
|
|
| MIT, ISC | **Yes** | Keep the notice |
|
|
| BSD 2-clause | **Yes** | Keep the notice |
|
|
| BSD 3-clause | **Yes** | Keep the notice; no endorsement claims |
|
|
| BSD **4-clause** (advertising) | **No** — see §3 | GPL-incompatible |
|
|
| GPL-2.0-only, GPL-2.0-or-later, LGPL-2.1 | **Yes** | Source for the combined work; keep the notices |
|
|
| MPL-2.0 | Case by case | Compatible through its secondary-licence clause, unless marked otherwise |
|
|
| Apache-2.0, GPL-3.0, LGPL-3.0 | **Not in the kernel**; separate programs and files fine | See below |
|
|
|
|
**Every "yes" above requires an entry in `NOTICE`.** That file is the project's
|
|
attribution record and the thing that makes the licences actually satisfied
|
|
rather than merely tolerated.
|
|
|
|
### One binary, one GPL version
|
|
|
|
"Or later" means SchOS code can go out under GPLv2 *or* GPLv3. A single linked
|
|
binary still has to pick one:
|
|
|
|
- Add **Linux code** (GPL-2.0-only) and that binary is GPLv2.
|
|
- Add **Apache-2.0 or GPLv3 code** and that binary is GPLv3, because
|
|
Apache-2.0's patent terms are "further restrictions" under GPLv2 §6.
|
|
|
|
Those two cannot meet in one binary. Linux is the main reason for the GPL, so
|
|
**the kernel stays GPLv2-compatible**: no Apache-2.0 or GPLv3 code is linked
|
|
into it. Userland programs are separate works, so one may be GPLv3 or
|
|
Apache-2.0 on its own without affecting anything else.
|
|
|
|
Data files such as fonts are not linked code. Roboto (Apache-2.0) sits beside
|
|
the system as an aggregate, and that holds inside the ramdisk too: the image is
|
|
a filesystem carried by the kernel binary, not code linked with it.
|
|
|
|
---
|
|
|
|
## 3. NetBSD in particular
|
|
|
|
`src-trunk/` is a NetBSD checkout kept as reference material and a parts bin
|
|
(see [plan/schapi.md](plan/schapi.md) §5). NetBSD is **not
|
|
uniformly licensed**, and the difference matters per file:
|
|
|
|
| Template | Status |
|
|
|---|---|
|
|
| 2-clause BSD — modern NetBSD Foundation files | **Fine** |
|
|
| 3-clause, "Regents of the University of California" | **Fine.** Berkeley formally rescinded the advertising clause in 1999 |
|
|
| 4-clause with the advertising clause, **non-UC** copyright holder | **No.** Berkeley's rescission covers Berkeley's copyright, not other people's, and the clause is GPL-incompatible |
|
|
|
|
The last row is real, not hypothetical. Measured on this checkout:
|
|
|
|
```
|
|
sys/kern 26 of 220 files carry the advertising clause
|
|
sys/dev 500 of 3565
|
|
lib/libc 101 of 1575
|
|
sys/net 5 of 180 ← the TCP/IP stack is nearly clean
|
|
```
|
|
|
|
4-clause is still permissive on its own, but the advertising clause is a
|
|
further restriction the GPL does not allow, so **a 4-clause file cannot be
|
|
combined with SchOS at all**. Use a 2-clause or UC-Regents file, or write it.
|
|
|
|
Check before copying, not after:
|
|
|
|
```sh
|
|
grep -l "All advertising materials" <file>
|
|
```
|
|
|
|
### And check *whose* clause it is
|
|
|
|
A file can carry several licence blocks from several copyright holders. Finding
|
|
the advertising clause is only half the check — Berkeley's rescission covers
|
|
Berkeley's copyright and nobody else's, so the question is always *whose*
|
|
clause you found.
|
|
|
|
Measured on `src-trunk`, the networking tree:
|
|
|
|
```
|
|
sys/net 106 files, 5 with the advertising clause
|
|
sys/netinet 121 files, 25 " " "
|
|
sys/netinet6 51 files, 5 " " "
|
|
```
|
|
|
|
Encouraging at first glance — the 25 in `sys/netinet` are almost all SCTP,
|
|
DCCP and multicast routing, none of which SchOS needs. `ip_input.c`,
|
|
`ip_output.c`, `udp_usrreq.c`, `if_arp.c`, `ip_icmp.c`, `if.c` and `route.c`
|
|
are all UC 3-clause, i.e. fine.
|
|
|
|
**But `tcp_input.c` and `tcp_output.c` are not.** Their advertising clause
|
|
belongs to the **WIDE Project** (the KAME IPv6 people), whose copyright sits at
|
|
the top of the file; the UC block is a separate licence further down. Berkeley
|
|
never spoke for WIDE, so the rescission does not reach it. The two most
|
|
valuable files in the stack are the two encumbered ones.
|
|
|
|
Under the GPL that rules them out, and it is exactly the case
|
|
where a **second BSD tree earns its disk space**: FreeBSD's TCP has been
|
|
through a relicensing effort NetBSD's has not, so the same file there may well
|
|
be 2-clause. Check it the same way before assuming either:
|
|
|
|
```sh
|
|
grep -n "Copyright" <file> | head # who claims it
|
|
grep -n -B6 "All advertising" <file> # whose clause is it
|
|
```
|
|
|
|
### FreeBSD's TCP is clean where NetBSD's is not
|
|
|
|
Checked, 2026-08-08, exactly that way. Against FreeBSD `main`:
|
|
`sys/netinet/tcp_input.c` contains **no advertising clause at all**. Its
|
|
copyright holders are the UC Regents, Swinburne University, Lawrence Stewart,
|
|
the FreeBSD Foundation and Juniper Networks -- all BSD-2 or BSD-3.
|
|
|
|
So if BSD networking code is taken, it must come from **FreeBSD, not NetBSD**,
|
|
and the specific reason is TCP. This reverses the earlier assumption in
|
|
`docs/plan/roadmap.md` that NetBSD was the intended starting point; NetBSD remains
|
|
the better-written reference to *read*, but FreeBSD is the one that can be
|
|
copied from.
|
|
|
|
|
|
### The third option: lwIP
|
|
|
|
Before porting either BSD stack, weigh **lwIP** against both. Verified
|
|
2026-08-08 from its `COPYING`: 3-clause BSD, Swedish Institute of Computer
|
|
Science, **no advertising clause anywhere in the file**. Compatible, one NOTICE
|
|
entry, done.
|
|
|
|
The licence is the smaller half of the argument. The larger half is that
|
|
FreeBSD's `sys/netinet` is not a library -- `tcp_input.c` alone is 122 KB and
|
|
reaches into mbufs, `epoch(9)`, netisr, VNET, `uma(9)`, sockbufs, inpcb hash
|
|
tables and FreeBSD's locking. Taking it means porting FreeBSD's kernel
|
|
infrastructure first and finding the TCP somewhere underneath, which is the same
|
|
conclusion `docs/guides/adding-a-driver.md` already reached about `sys/dev/usb`.
|
|
|
|
lwIP was written for the case SchOS is in: a small operating system with a raw
|
|
Ethernet driver and no infrastructure to speak of. Its port layer is a handful
|
|
of files, it has no dependency on the host kernel's allocator or locking, and it
|
|
brings ARP, IPv4, ICMP, UDP, TCP, DHCP and DNS.
|
|
|
|
### uACPI
|
|
|
|
The AML interpreter, `ports/uacpi`, compiled into the kernel like lwIP.
|
|
Verified 2026-10-22 from its `LICENSE`: MIT, Daniil Tatianin. Compatible, one
|
|
NOTICE entry. The choice over ACPICA was not about licensing but size: uACPI
|
|
asks a host for far less, and its whole host side is `kernel/acpi/host.c`.
|
|
|
|
### Fonts
|
|
|
|
Chosen 2026-08-09, both licences checked at source rather than assumed:
|
|
|
|
| Font | Where | Licence |
|
|
|---|---|---|
|
|
| Roboto | desktop, window manager, compositor | **Apache-2.0** |
|
|
| JetBrains Mono | terminal, TTY | **SIL OFL 1.1** |
|
|
|
|
Roboto is Apache-2.0, which is fine for a font: it is a data file beside the
|
|
system, not code linked into it (§2). A NOTICE entry and nothing else.
|
|
|
|
OFL is permissive and bundling is precisely what it is for, with two conditions
|
|
worth knowing before anyone subsets or converts a font:
|
|
|
|
- **The font stays under OFL** even inside a GPL-licensed system. It does not
|
|
infect anything else; it just cannot be relicensed.
|
|
- **It may not be sold on its own.** Shipping it as part of an OS is fine.
|
|
- **Reserved Font Names.** JetBrains Mono declares *none* -- its copyright line
|
|
names no reserved name -- so a modified version may keep the name. Most OFL
|
|
fonts do reserve theirs, and then a derivative must be renamed.
|
|
Pre-rasterising a font into bitmaps at build time **is** a modification, so
|
|
this is not a theoretical point for this project.
|
|
|
|
---
|
|
|
|
## 4. Things that are deliberately not shipped
|
|
|
|
Some code is fine to *build and run locally* and impossible to *distribute*
|
|
with SchOS. Keeping the distinction sharp is what stops it eroding:
|
|
|
|
- **`Refrence/`** — a FreeBSD checkout (`Refrence/freebsd-src`), kept as
|
|
reference material and a parts bin. Never built, never in an image. The
|
|
directory name is spelled as it is on disk; renaming it is a one-line change
|
|
if it ever grates.
|
|
- **`src-trunk/`** — a NetBSD checkout, same rules. Currently absent; it was
|
|
deleted for disk space and can be re-fetched sparsely if needed.
|
|
- **`dist/`** — upstream tarballs and other downloaded blobs. Cached so a
|
|
rebuild never needs the network; not part of any image, and not all of it is
|
|
redistributable.
|
|
|
|
### The userland, and why it is permissive anyway
|
|
|
|
While SchOS was Apache-2.0, **BusyBox** (GPL-2.0-only) and **nano** (GPL-3.0)
|
|
were ruled out, and the userland was built from toybox (0BSD), mksh and kilo
|
|
(BSD-2-Clause) instead. Both would be possible now — nano as a separate program
|
|
— but nothing needs replacing: toybox gives 268 applets, kilo is installed as
|
|
`/bin/edit`, and `cmd/httpd` is first-party.
|
|
|
|
The `wget` failure that started that discussion was not a userland problem:
|
|
SchOS had no DNS reachable from a process, which BusyBox would have hit
|
|
identically. See [architecture/networking.md](architecture/networking.md).
|
|
|
|
The mechanisms that keep this from eroding, since good intentions have already
|
|
failed once here:
|
|
|
|
- `NOTPORTS` in `ports/Makefile` — a port that lives in the tree but is never
|
|
built by `make`.
|
|
- `RAMDISK_EXCLUDE` in the root `Makefile` — paths kept out of the ramdisk root.
|
|
This one matters more than it looks: the ramdisk image is linked *into the
|
|
kernel binary*, so anything sitting in `sysroot/` when that image is built
|
|
becomes part of a distributable artifact. A GPL-2.0 or non-redistributable
|
|
file staged there does not merely ride along, it makes the kernel itself
|
|
undistributable.
|
|
|
|
A previous acceptance test — a ported 1993 shooter, GPL-2.0 engine on
|
|
non-redistributable shareware data — was carried under exactly these rules and
|
|
has since been removed. It is worth recording *why* it was safe: it was never in
|
|
`PORTS`, and its 33 MB of data was excluded from the ramdisk. It is equally
|
|
worth recording that the safety depended on two separate opt-outs staying
|
|
correct, which is a lot of standing risk for a test that had stopped finding
|
|
bugs. See `docs/guides/testing.md`.
|
|
|
|
---
|
|
|
|
## 5. Specifications are not code
|
|
|
|
A published specification carries no copyright over an independent
|
|
implementation of it. The xHCI, USB, PCI, fbdev and ELF specifications were all
|
|
read and implemented directly, which is why those drivers have no licence
|
|
entanglement at all despite equivalents existing in both Linux and BSD.
|
|
|
|
When a subsystem is small enough to write from the spec, that is usually the
|
|
cheapest option in the long run — not because copying is hard, but because a
|
|
copied file is a file to be understood, attributed and maintained forever.
|
|
|
|
---
|
|
|
|
## 6. LDLS, and the distribution boundary
|
|
|
|
[architecture/ldls.md](architecture/ldls.md) runs Linux drivers. This section
|
|
was written when SchOS was Apache-2.0 and the boundary below was a legal
|
|
necessity. Under GPL-2.0-or-later it is a **project policy** instead: shipping
|
|
a GPL-2.0-only `.ko` with SchOS would now be lawful, provided the source goes
|
|
with it. It is still not done, because a module we never ship is a module we
|
|
never have to vouch for, track upstream, or provide source for.
|
|
|
|
### LDLS is ours
|
|
|
|
Every file under `ldls/` is ours, GPL-2.0-or-later. The loader was written from
|
|
the ELF-64 gABI and the x86-64 psABI; the shim is written under the rule in
|
|
[architecture/ldls.md](architecture/ldls.md). Copying Linux code into it would
|
|
no longer be a licence problem, but the shim's value is that it is small and
|
|
understood, so the existing rule stands.
|
|
|
|
### The combination is the user's
|
|
|
|
| | licence | who distributes it |
|
|
|---|---|---|
|
|
| `ldls/` — loader, shim, host | **GPL-2.0-or-later** | us |
|
|
| a `.ko` | GPL-2.0-only, usually | the user's distribution |
|
|
| the two running together in a process | — | **nobody** |
|
|
|
|
GPLv2 §0 is explicit about where its obligations attach:
|
|
|
|
> Activities other than copying, distribution and modification are not covered
|
|
> by this License; they are outside its scope. **The act of running the Program
|
|
> is not restricted.**
|
|
|
|
So: we ship LDLS and no modules. The user obtains a module from wherever they
|
|
get their software and runs it on their own machine. `RAMDISK_EXCLUDE` and the
|
|
`*.ko` rule in `.gitignore` keep that boundary mechanical rather than
|
|
intentional.
|
|
|
|
### `EXPORT_SYMBOL_GPL` does not apply
|
|
|
|
Linux marks much of its internal API `EXPORT_SYMBOL_GPL`, and modules carry
|
|
`MODULE_LICENSE`. Supplying those symbols while asserting a licence one does
|
|
not hold would be circumvention, and it is worth saying why LDLS is not doing
|
|
that.
|
|
|
|
**LDLS has no Linux symbols to gate.** `EXPORT_SYMBOL_GPL` is Linux marking
|
|
*Linux's own* symbols, and the check it drives protects those. Every symbol
|
|
LDLS provides is ours — reimplemented from facts, under GPL-2.0-or-later. There is no
|
|
gate being bypassed, because there is no Linux symbol being exposed.
|
|
|
|
So LDLS implements no licence check. It **reads** the module's declared licence
|
|
and prints it before loading anything, because that is the one property that
|
|
decides whether an object should be on a machine at all and it costs nothing to
|
|
show.
|
|
|
|
### BTF: the layouts are not in our source at all
|
|
|
|
§3 of the plan has one uncomfortable row — struct layouts. A compiled driver
|
|
indexes fields by offset, so the shim has to reproduce them exactly, and a
|
|
field-for-field match *looks* like transcription even when it is not.
|
|
|
|
It does not have to be in our source. Kernels built with `CONFIG_DEBUG_INFO_BTF`
|
|
— which is most distribution kernels — publish `/sys/kernel/btf/vmlinux`, and
|
|
that file carries both halves of what the shim needs:
|
|
|
|
```
|
|
struct pci_dev {
|
|
struct list_head bus_list; /* 0 16 */
|
|
struct pci_bus * bus; /* 16 8 */
|
|
...
|
|
|
|
[97814] FUNC 'pci_iomap' type_id=97813 linkage=static
|
|
[97815] FUNC_PROTO '(anon)' ret_type_id=108 vlen=4
|
|
```
|
|
|
|
Layouts **and** prototypes, as generated binary type data describing the kernel
|
|
the user already has installed. LDLS can read them at load time, on the user's
|
|
machine, from the user's own kernel — so our source contains neither, and there
|
|
is nothing to have transcribed.
|
|
|
|
Three things improve together: the provenance question largely disappears, the
|
|
version-pinning problem (plan §4) mostly dissolves because BTF describes the
|
|
kernel that is actually there, and it is less work than writing hundreds of
|
|
struct definitions by hand.
|
|
|
|
**What BTF does not give is behaviour.** It says `napi_complete_done` takes
|
|
these arguments and returns that type. What it *does* is still ours to
|
|
implement from documentation, and that is the real work — BTF does not touch
|
|
it.
|