licence: SchOS is GPL-2.0-or-later, no longer Apache-2.0

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>
This commit is contained in:
Nexoniarz 2026-10-22 08:48:45 +02:00
commit 26bca020b6
135 changed files with 959 additions and 689 deletions

View file

@ -7,24 +7,31 @@ pointed here long before this file existed.
---
## 1. SchOS is Apache-2.0
## 1. SchOS is GPL-2.0-or-later
Copyright Nexoniarz. See `LICENSE`.
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.
Apache-2.0 was chosen over MIT/BSD for one reason that actually matters at OS
scale: it contains an **express patent grant** and a patent-retaliation clause.
MIT and BSD are silent on patents, which means a contributor can hand you code
and later assert a patent over it. For a kernel that is intended to accept
outside contributions, that silence is the expensive kind.
**Why the GPL.** Two reasons, one about others and one about us:
What that grant means in practice: Apache-2.0 §2 gives everyone a perpetual,
worldwide, irrevocable licence to reproduce, modify, sublicense and distribute
SchOS. Any additional restriction stated elsewhere — in a README, a website,
or a policy — does not narrow it. The licence text is what holds up.
- **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).
If restricted distribution is ever genuinely wanted, that is a licence change
(a bespoke proprietary licence, or something like BUSL-1.1 with a conversion
date), not a wording change, and it means giving up the Apache grant.
**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`.
---
@ -36,37 +43,32 @@ date), not a wording change, and it means giving up the Apache grant.
| 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) | **Avoid** — see §3 | Notice *and* an acknowledgement in advertising materials |
| Apache-2.0 | **Yes** | Keep NOTICE contents |
| MPL-2.0 | Case by case | File-level copyleft; keep those files separate |
| **GPL-2.0-only** | **No** | — |
| **GPL-3.0 / LGPL-3.0** | **No** for linked code | — |
| 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 permissive licences actually
satisfied rather than merely tolerated.
attribution record and the thing that makes the licences actually satisfied
rather than merely tolerated.
### Why GPL-2.0-only is a hard no
### One binary, one GPL version
Apache-2.0 imposes conditions GPLv2 treats as "further restrictions" under its
§6 — principally the patent-retaliation term. The FSF and the ASF agree on
this: **Apache-2.0 code and GPL-2.0-only code cannot be combined into one
distributable work.** It is not a matter of taste or of how carefully the files
are kept apart in the tree; it is that the combined binary cannot satisfy both
licences at once.
"Or later" means SchOS code can go out under GPLv2 *or* GPLv3. A single linked
binary still has to pick one:
GPL-3.0 fixed this in the other direction (Apache-2.0 is compatible *into*
GPLv3), but that does not help: the result would have to ship under GPLv3, and
SchOS does not.
- 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.
**Practical consequence:** BSD drivers can be adopted. Linux drivers cannot,
ever, no matter how convenient. This is why the USB stack was written from the
specification rather than ported.
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.
**"Cannot be adopted" is not the same as "cannot be run."** A driver the *user*
obtains and loads on their own machine is their act, not a distribution by us —
see §4 and [architecture/ldls.md](architecture/ldls.md), which is the layer built on exactly
that distinction and which ships no Linux code of any kind.
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.
---
@ -80,7 +82,7 @@ uniformly licensed**, and the difference matters per file:
|---|---|
| 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 | **Avoid.** Berkeley's rescission covers Berkeley's copyright, not other people's |
| 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:
@ -91,10 +93,9 @@ lib/libc 101 of 1575
sys/net 5 of 180 ← the TCP/IP stack is nearly clean
```
4-clause is still permissive and still redistributable; the burden is an
advertising obligation that accumulates quietly and is tedious to honour
properly. Prefer a 2-clause or UC-Regents file. If a 4-clause file is genuinely
the right answer, it goes into `NOTICE` with the full clause quoted.
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:
@ -128,7 +129,7 @@ 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.
That is not fatal — 4-clause is still permissive — but it is exactly the case
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:
@ -180,13 +181,13 @@ Chosen 2026-08-09, both licences checked at source rather than assumed:
| Roboto | desktop, window manager, compositor | **Apache-2.0** |
| JetBrains Mono | terminal, TTY | **SIL OFL 1.1** |
Roboto is the same licence as SchOS, so it is the easy case: a NOTICE entry
and nothing else.
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 an Apache-2.0 system. It does not
- **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
@ -212,42 +213,17 @@ with SchOS. Keeping the distinction sharp is what stops it eroding:
rebuild never needs the network; not part of any image, and not all of it is
redistributable.
### The userland this rules out, and what was done instead
### The userland, and why it is permissive anyway
The rule costs something real and it is worth naming the bill rather than only
the principle.
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.
**BusyBox** is the obvious userland for a system this size — about four hundred
applets, including a shell, an editor, `less` and an `httpd`. It is
**GPL-2.0-only**, so §2 applies, and here the consequence is sharper than
"cannot be linked": `make ramroot` links the root filesystem image *into the
kernel binary*, so a BusyBox in `sysroot/` would put GPLv2 code inside an
Apache-2.0 executable. Excluding it from the ramdisk avoids that and leaves the
ramroot build with no userland at all, which is not a trade worth making.
**nano** is the same answer for the same reason, one version later: GPL-3.0,
which is incompatible with Apache-2.0 in the other direction.
What was done instead, when the complaint "the userland is too thin" came up:
| wanted | answer |
|---|---|
| `awk`, `bc`, `diff`, `more`, `expr`, `tr`, … | already in toybox, in `toys/pending/`, switched off by `defconfig`. Turning 26 of them on took the shipped set from 236 applets to 268, at no licensing cost — it is the same 0BSD tarball. |
| an editor that is not `vi` | [kilo](https://github.com/antirez/kilo), BSD-2-Clause, one file, no dependencies. Installed as `/bin/edit` as well as `/bin/kilo`. |
| `wget` that works | not a userland problem at all. See below. |
| something to host with | `cmd/httpd`, written here, Apache-2.0. |
The `wget` one is worth recording because it was diagnosed wrongly at first,
and switching userland would not have fixed it: **SchOS had no DNS reachable
from a process**, so every program taking a hostname failed and each looked
like its own bug. BusyBox's `wget` would have failed identically. musl already
contains a complete resolver; the only missing fact was which nameserver, which
the kernel had all along from DHCP and never published. See
[architecture/networking.md](architecture/networking.md).
The general shape: **a permissive answer existed for every one of these**, and
three of the four were already in the tree. That will not always be true, and
when it is not the answer is still no.
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:
@ -286,22 +262,26 @@ 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. That sounds like it should
contradict §2, and it does not, because the two questions below are different
ones and only the first is about us.
[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 Apache-2.0
### LDLS is ours
Every file under `ldls/` is ours. 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). **No Linux code is in it and none ever will
be**, which is the same standard the xHCI and USB stacks already meet (§5).
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 not ours to make
### The combination is the user's
| | licence | who distributes it |
|---|---|---|
| `ldls/` — loader, shim, host | **Apache-2.0** | us |
| `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** |
@ -311,20 +291,10 @@ GPLv2 §0 is explicit about where its obligations attach:
> by this License; they are outside its scope. **The act of running the Program
> is not restricted.**
So: we ship Apache-2.0 code containing no GPL. The user obtains a GPL module
from wherever they get their software. The user runs them together on their own
machine. No combined work is distributed by anyone, and no GPL obligation is
triggered — not on us, and not on them.
This is the position FreeBSD has shipped from for about a decade: a
BSD-licensed `linuxkpi` in base, GPL `drm-kmod` installed by the user from
ports.
**The consequence for the user, stated plainly:** they cannot redistribute the
combination either. An image with a `.ko` baked into it is a single work that
would have to satisfy Apache-2.0 and GPL-2.0-only at once, which §2 explains is
impossible. That is why `RAMDISK_EXCLUDE` exists, and why `.gitignore` refuses
`*.ko` outright — the boundary is kept mechanically rather than by intention.
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
@ -335,7 +305,7 @@ 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 Apache-2.0. There is no
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