ldls: Apache-2.0, and where the boundary actually is
Answers the question directly in docs/licensing.md §6, because "LDLS runs Linux drivers" reads like it contradicts §2 and does not. LDLS is Apache-2.0. Every file under ldls/ is ours; the loader came from the ELF-64 gABI and the x86-64 psABI. The licence of LDLS and the licence status of what happens at run time are two different questions and only the first is about us: ldls/ Apache-2.0 distributed by us a .ko GPL-2.0 distributed by the user's distro the two in one process -- distributed by nobody GPLv2 §0 says where its obligations attach -- "the act of running the Program is not restricted" -- so no combined work is distributed by anyone and no obligation is triggered. Same position FreeBSD has shipped from for a decade. Stated honestly in the same section: the *user* cannot redistribute the combination either, which is why RAMDISK_EXCLUDE exists and why .gitignore refuses *.ko. EXPORT_SYMBOL_GPL was left open in the plan; it is now answered and the answer is cleaner than expected. That marking gates *Linux's own* symbols. Every symbol LDLS provides is ours, reimplemented from facts, so there is no gate being bypassed because no Linux symbol is being exposed. LDLS implements no licence check -- it reads the declared licence and prints it before loading anything. And the sharpest edge in rule 3 mostly goes away. The uncomfortable row was struct layouts, which a compiled driver indexes by offset, so the shim must 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 publish /sys/kernel/btf/vmlinux, and that carries both the layouts and the function prototypes as generated type data about the kernel the user already has. Verified on this machine: struct pci_dev field by field, and FUNC 'pci_iomap' with its FUNC_PROTO. LDLS reads them at load time on the user's machine; our source contains neither. That also mostly dissolves rule 4, since BTF describes the kernel that is actually installed rather than one pinned by guessing. What BTF does not give is behaviour -- what napi_complete_done *does* is still ours to write from documentation, and that is the whole of the real work. Also adds the SPDX header ldls/ko.h was missing. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01VQ7Qx8E1q1M1bbCq8QLHS2
This commit is contained in:
parent
1be5f3a704
commit
901ae03a69
3 changed files with 140 additions and 8 deletions
|
|
@ -244,3 +244,99 @@ 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
|
||||
|
||||
[plan/ldls.md](plan/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.
|
||||
|
||||
### LDLS is Apache-2.0
|
||||
|
||||
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
|
||||
[plan/ldls.md](plan/ldls.md) §3. **No Linux code is in it and none ever will
|
||||
be**, which is the same standard the xHCI and USB stacks already meet (§5).
|
||||
|
||||
### The combination is not ours to make
|
||||
|
||||
| | licence | who distributes it |
|
||||
|---|---|---|
|
||||
| `ldls/` — loader, shim, host | **Apache-2.0** | 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 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.
|
||||
|
||||
### `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 Apache-2.0. 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.
|
||||
|
|
|
|||
Loading…
Reference in a new issue