
QRV Sistema Operativo
QRV è un adattamento e una reimplementazione da zero del sistema operativo QNX Neutrino
6.4 per hardware moderno a 64 bit, con RISC-V (rv64g) come architettura
principale e x86-64 come target secondario. Il progetto è iniziato la vigilia
di Natale del 2020. Il nome QRV evita deliberatamente qualsiasi associazione con il marchio QNX.
QRV è un sistema operativo completo, non solo un kernel. Il microkernel è il suo
cuore — ma la parte più cospicua del lavoro è stata dedicata a tutto ciò che lo
circonda. La cosa più importante è taskman, il gestore di processi / memoria / path
in modalità utente (il procnto di QNX), che è stato profondamente rielaborato e
spostato dal kernel allo spazio utente; insieme ad esso, la libreria C, i driver
di dispositivo, il filesystem, il loader dinamico e i server di sistema sono stati
tutti portati, resi compatibili con il 64 bit e in molti casi pesantemente riscritti.
Il microkernel è piccolo per progettazione; il sistema operativo che lo circonda è
dove vive la maggior parte di QRV.
Questo non è un fork che si limita a compilare vecchio codice con un nuovo compilatore.
È un porting attento, modulo per modulo, a un vero modello LP64, con il
confine proprietario di procnto smantellato, il meccanismo IFS/startup
sostituito e — a partire dalle release più recenti — il Big Kernel Lock del kernel
completamente rimosso e il gestore di processi/memoria/path spostato dal kernel
a un server in modalità utente.
Questo README descrive QRV v0.43.
Il blog di sviluppo, con la storia completa del porting, si trova all'indirizzo
https://r-tty.blogspot.com. Una narrazione della lunghezza di un libro, The QRV Porting
Story, risiede nell'albero dei sorgenti sotto doc/tex/PortingStory/.
QRV è stato sviluppato in stretta collaborazione con Claude Code, lo strumento di codifica agentico di Anthropic — gran parte del porting, del debugging SMP e della documentazione (incluso questo README) è stata svolta come uno sforzo di programmazione in coppia umano–AI, lavorando insieme all'autore.
obtain_proj.sh e l'albero os/TM_PRIVdevb-nvme e fs-qrvQNX è un sistema operativo real-time a microkernel la cui idea fondamentale è il message passing sincrono. In QNX, il kernel stesso è minuscolo — sa come schedulare thread, passare messaggi, consegnare segnali, gestire timer e interrupt, e poco altro. Tutto ciò che un sistema operativo monolitico metterebbe dentro il kernel — il gestore dei processi, il gestore della memoria, il filesystem, i driver di dispositivo, lo stack di rete — viene eseguito in normali processi utente chiamati resource manager, e comunicano tra loro e con i loro client attraverso la stessa primitiva IPC send / receive / reply.
Questa architettura è ciò che rende QNX elegante, ed è esattamente ciò che QRV preserva. Un programma che vuole aprire un file invia un messaggio; il server del filesystem lo riceve, esegue il lavoro e risponde. Il kernel orchestra solo l'appuntamento. Il risultato è un sistema in cui un driver può crashare e essere riavviato senza far cadere il kernel, in cui la base di calcolo fidata è misurata in decine di kilobyte, e in cui il confine tra "kernel" e "applicazione" è un messaggio, non una barriera di privilegi piena di syscall.
QRV prende i sorgenti della comunità di QNX Neutrino 6.4 del 2009 e porta avanti quel progetto:
int/uint32_t/pid_t-su-puntatore
di cui il codice a 32 bit è pieno.qemu-system-riscv64 (la macchina
virt) e la scheda di sviluppo SiFive Unmatched (FU740). x86-64 viene
mantenuto in compilazione come controllo di portabilità.mkifs (QRV usa
il formato standard CPIO); non c'è una separazione separata
startup/kernel (lo startup è linkato direttamente con il kernel); non ci
sono callout e mini-driver.Kconfig stile Linux, un link
incrementale del kernel (i moduli vengono aggiunti e testati uno alla volta, non lanciati
al linker come un monolito da 32→64) e una toolchain cross-compilatore
(riscv64-linux-gnu-gcc).procnto è taskman (il
Task Manager) dappertutto; tutti i riferimenti a "Neutrino" sono rimossi.QRV non implementa fork() (i programmi partono tramite posix_spawn()),
e non ha paging su domanda e nessuno swap — le stesse scelte che QNX stesso
ha fatto nella sua generazione 8.0.
QRV è governato da due licenze contemporaneamente, e capire quale sia quale è essenziale prima di compilare o ridistribuire qualsiasi cosa.
Il codice proprio di QRV è sotto licenza Apache 2.0. Tutto ciò che è scritto da zero
per questo progetto — il porting RISC-V, il nuovo sistema di build, la separazione
di taskman in modalità utente, la rielaborazione del kernel senza lock, i driver e gli strumenti che
abbiamo creato — è Apache 2.0. Il testo completo è in LICENSE.txt.
Il codice derivato da QNX è sotto BlackBerry QNX Community License (QCL) 2.0. Le parti di QRV che discendono dai sorgenti della comunità di QNX Neutrino del 2009 rimangono sotto la QCL, che permette l'uso non commerciale e accademico dei sorgenti derivati. QRV non rilascia, e non può rilasciare, il codice di QNX sotto altra licenza.
Questa realtà della doppia licenza è precisamente il motivo per cui questo repository non contiene un albero dei sorgenti pronto per la compilazione. Non ci è permesso ridistribuire i sorgenti derivati da QNX. Quindi invece di distribuire il codice, questo repository distribuisce una ricetta (vedi la sezione successiva): una mappa di dove va ogni file QNX, più le patch QRV che lo trasformano. Tu ottieni i sorgenti della comunità QNX upstream da solo, dal loro mirror pubblico, e la ricetta ricostruisce l'albero QRV sulla tua macchina. La tua copia è tua; noi ridistribuiamo solo le nostre patch e metadati sotto licenza Apache.
QRV incorpora anche codice sotto altre licenze permissive — per esempio
componenti con licenza BSD adottati da FreeBSD (che sostituiscono moduli QNX invecchiati),
un driver di blocco virtio con licenza MIT di derivazione xv6, e la MirBSD Korn
shell (mksh) come shell di sistema. WHAT_IS_WHAT.md è la mappa autorevole,
componente per componente di cosa è sotto quale licenza e da dove
proviene — consultalo ogni volta che non sei sicuro su un particolare file o
sottosistema.
Infine, il repository contiene PETITION.md: una richiesta aperta a QNX
Software Systems e BlackBerry di rilasciare i sorgenti storici di Neutrino
2007–2009 sotto una licenza permissiva approvata dall'OSI. Se desideri
che le fondamenta di questo lavoro siano un giorno completamente libere, quel documento è
dove aggiungere il tuo nome.
obtain_proj.sh e l'albero os/Poiché i sorgenti derivati da QNX non possono essere ridistribuiti qui, questo repository è una distribuzione a ricostruzione dei sorgenti. Contiene:
$ ./obtain_proj.sh
1. **Clona il mirror della community upstream di QNX** (`github.com/vocho/openqnx`,
un clone shallow).
2. **Posiziona i file** secondo `placement.txt`, copiando ogni file upstream
nella sua posizione QRV sotto `os/`. Riporta quanti file sono stati
posizionati, già presenti o mancanti.
3. **Rimuove il clone** una volta completato il posizionamento.
4. **Applica la serie di patch QRV** da `patches/series`, in ordine. Ogni
patch è compressa con LZ4 (`*.patch.lz4`) e applicata con
`lz4cat … | patch -p1`. Le patch portano la versione della release corrente.
5. **Imposta i permessi eseguibili** sulla manciata di script che ne hanno bisogno
(ad es. `emu.sh`, `host_tools/mkgpt.py`).
Gli strumenti necessari sono `git`, `patch` e `lz4cat` (dal pacchetto
`lz4`); lo script li controlla in anticipo e ti dice come installare
quelli mancanti.
Il prodotto finale è **`os/`** — un albero sorgente QRV completo e compilabile:```
os/
├── kernel/ Everything linked into the qrv-kernel binary
│ ├── arch/riscv/ RISC-V port: vectors, traps, SBI, context switch,
│ │ ├── startup/ arch-specific startup (head.S, mmu.c, …)
│ │ ├── platform/ qemu_virt/, unmatched/
│ │ └── include/ context.h, cpu_paging.h, sbi.h, …
│ ├── startup/ arch-independent startup (hardware_init, smp, …)
│ ├── nano/ core nanokernel: messaging, scheduling, sync, xfer
│ ├── kext/ kernel extensions (kerexts)
│ └── include/ kernel-internal headers
├── taskman/ The Task Manager (QNX's "procnto"), a user-mode server
│ ├── sys/ system manager: main, ELF loader, support
│ ├── proc/ process manager: spawn, wait, …
│ ├── mem/ memory manager: page tables, physical allocator
│ │ └── pageman/ page-granularity virtual-memory operations
│ └── path/ path manager: namespace, /dev/*, /proc/*
├── lib/ C library and runtime
├── include/ User-space-visible headers (the public ABI)
├── userland/ Shell, utilities, drivers, servers (resource managers)
├── servers/ pci, slogger
├── dev/ Device drivers (virtio block, 8250 UART, …)
├── boot/ Boot artifacts and deploy helpers
├── host_tools/ Host-side tooling (mkgpt.py, …)
├── doc/ Documentation, incl. The QRV Porting Story (LaTeX)
├── Kconfig, Makefile, def.mk, common.mk, emu.sh
Da lì, cd os && make costruisce il sistema (vedi §9).
QRV è un vero sistema microkernel. La stack dei privilegi, dall'hardware in su, appare così su RISC-V:``` ┌───────────────────────────────────────────────────────────────────────┐ │ User space (U-mode) │ │ │ │ sh pidin lspci sloginfo login ... │ │ │ │ │ │ │ │ │ devb-nvme fs-qrv devc-ser* pci slogger ← resource managers │ │ │ │ │ │ │ │ │ │ └──────┴───────┴────────┴─────────┴───────┘ │ │ │ libc (send / receive / reply stubs) │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ taskman — process · memory · path manager │ │ │ │ a U-mode server, privileged via TM_PRIV │ │ │ └─────────────────────────────────────────────────────────────────┘ │ └────────────────────────────────────│──────────────────────────────────┘ │ ecall (syscall / message) ┌───────────────────────────────────────────────────────────────────────┐ │ QRV microkernel (S-mode) │ │ │ │ message passing · channels & connections · scheduling · │ │ threads · synchronization · signals · timers & clocks · │ │ interrupts · syscall dispatch · TM_PRIV kernel extensions │ └───────────────────────────────────────│───────────────────────────────┘ │ SBI ecall ┌───────────────────────────────────────────────────────────────────────┐ │ OpenSBI firmware (M-mode) │ └───────────────────────────────────────│───────────────────────────────┘ │ ┌───────────────────────────────────────────────────────────────────────┐ │ RISC-V 64-bit hardware — QEMU virt · SiFive Unmatched U740 │ └───────────────────────────────────────────────────────────────────────┘
**Il kernel (S-mode)** è l'unico componente che opera in modo privilegiato nel senso classico. I suoi sottosistemi sono piccoli e focalizzati:
- **Passaggio di messaggi** — `ker_message.c`, `ker_fastmsg.c`, `nano_message.c`
- **Canali e connessioni** — `ker_channel.c`, `ker_connect.c`
- **Thread e scheduling** — `ker_thread.c`, `ker_sched.c`, `nano_sched.c`
- **Sincronizzazione** — `ker_sync.c`, `nano_sync.c`
- **Segnali** — `ker_signal.c`
- **Timer e clock** — `ker_timer.c`, `ker_clock.c`
- **Interrupt** — `ker_interrupt.c`
- **Dispatch delle syscall** — `ker_call_table.c`
- **Trasferimento dati** — la famiglia `nano_xfer*.c` (il motore di copia cross-address-space che sposta in sicurezza i payload dei messaggi tra i processi)
L'interfaccia tra il bootstrapper e il kernel è la **syspage** (`include/sys/syspage.h`); lo stato per-CPU risiede nella **cpupage**; il contesto completo dei registri è `RISCV_CPU_REGISTERS`. Su RISC-V, ogni "CPU" è identificata ovunque dal suo **hart ID** — esiste un unico namespace per la denominazione delle CPU, end-to-end.
**Tutto il resto è un processo utente.** Il gestore di processi/memoria/percorsi, i driver di blocco e seriale, il filesystem, il server PCI, il logger di sistema — tutti sono resource manager raggiungibili inviando un messaggio. Il kernel non contiene un filesystem; contiene la capacità per un processo di chiedere a un altro di *essere* un filesystem.
---
## 5. Taskman e la syscall privilegiata `TM_PRIV`
**`taskman`** è il nome che QRV dà a ciò che QNX chiamava `procnto`: il **gestore combinato di processi, memoria e percorsi (namespace)**. In un classico sistema QNX questo codice è fuso nell'immagine del kernel. Uno dei più grandi risultati strutturali di QRV è che **taskman ora gira in modalità utente** — è un normale processo U-mode, non parte del kernel privilegiato.
Sorge una domanda ovvia: se taskman vive nello spazio utente, come fa a compiere le operazioni profondamente privilegiate che un gestore di processi e memoria deve fare — manipolare le tabelle delle pagine, allocare RAM fisica, creare e distruggere spazi di indirizzamento, consegnare segnali e impulsi, terminare processi?
La risposta è un singolo, strettamente controllato gateway: **`__KER_TM_PRIV`**, syscall slot 2. È l'unica porta attraverso cui taskman accede alle operazioni privilegiate del kernel, e dietro a quel singolo slot si trova una tabella di dispatch di **~98 sotto-operazioni** — piccole **estensioni del kernel** ("kerexts") che eseguono ciascuna una singola azione privilegiata ben definita e restituiscono il controllo. Alcune famiglie rappresentative:
- **Ciclo di vita dei processi** — `PROCESS_CREATE`, `PROCESS_EXEC`,
`PROCESS_DESTROY`, `PROCESS_STARTUP`, `PROCESS_SHUTDOWN`, `REPARENT`
- **Memoria fisica e virtuale** — `PA_ALLOC`, `PA_FREE`,
`PA_QUANTUM_TO_PADDR`, `PAGE_CONT`, `STACK_CONT`, `ASPACE_MEMCPY`
- **Credenziali e limiti** — `CRED_GET`, `CRED_SET`, `LIMITS_GET/SET`
- **Consegna e oggetti** — `PULSE_DELIVER`, `SIGNAL_DELIVER`,
`QUERY_OBJECT`, `CHANNEL_DESTROY`, `CONNECT_DETACH`
- **SMP e piattaforma** — `SMP_BRINGUP`, `LEGAL_CPU_MASK`, `GET_KERN_PGDIR`,
`ICACHE_SYNC` (l'operazione di coerenza della cache delle istruzioni RISC-V, nuova dalla v0.43)
Questo design mantiene **piccola la base di computazione fiduciaria** — il kernel effettivo rimane minimale — dando a taskman esattamente le primitive privilegiate di cui ha bisogno e **niente di più**. Fondamentalmente, l'heap del kernel e altri interni del kernel rimangono inaccessibili alla modalità U (le pagine del kernel mantengono `PTE_U=0`); taskman svolge il suo lavoro attraverso kerexts di copia-in/copia-out, senza mai ricevere un puntatore grezzo al kernel. L'enum risiede in `kernel/include/ker+tm/tm_kercalls.h`; la tabella di dispatch è in `kernel/ker_tm_priv.c`.
---
## 6. Il Big Kernel Lock — e la sua rimozione
Il primo QRV — come la generazione QNX da cui deriva sui sistemi multiprocessore — proteggeva il kernel con un singolo **Big Kernel Lock (BKL)**: una parola globale `inkernel` che ammetteva esattamente un hart nel kernel alla volta. Non importa quante CPU stessero girando, ogni chiamata di sistema e ogni messaggio di taskman si serializzava attraverso quel singolo lock. Corretto, semplice — e un tetto duro sulla scalabilità SMP.
**A partire dalla v0.42, il BKL è stato rimosso.** Questo è stato il titolo di una lunga serie di release candidate e il soggetto dei capitoli 9–14 di *The QRV Porting Story*. Le chiamate di sistema e i messaggi di taskman ora girano **concorrentemente tra gli hart** sotto lock fini, per-oggetto:
- **Blocco per-oggetto.** Un lock per-`tChannel` e un lock per-`tConnect` proteggono le code dei messaggi; un `vec_slock` per-processo protegge il vettore dei thread; un `sched_slock` per-dispatch protegge le code di esecuzione; un `alloc_slock` protegge l'heap del kernel.
- **Passaggio di messaggi senza blocco (lock-free).** `MsgSend` / `MsgReceive` / `MsgReply` e la famiglia `Sync*` non prendono **alcun lock globale**. Il rendezvous cross-hart è coordinato da bit bridge per-thread e memory fence hardware piuttosto che da mutua esclusione.
- **Reclamo SMR (equivalente RCU).** Thread, connessioni e canali vengono ritirati attraverso safe-memory-reclamation in modo che le ricerche lock-free non dereferenzino mai un oggetto deallocato.
Su QEMU `virt` con `-smp 8`, il kernel si avvia in modo affidabile fino al prompt `login:` e sostiene un ciclo di stress `pidin` di 300 iterazioni senza stalli.
---
## 7. Storage: `devb-nvme` e `fs-qrv`
Fedeli al modello microkernel, lo storage in QRV è composto da **due processi utente cooperanti**, non da un sottosistema del kernel:
- **`devb-nvme`** — il driver di dispositivi a blocchi. Parla NVMe su PCIe (con parsing delle partizioni GPT integrato), scopre il controller attraverso il server PCI e presenta dispositivi a blocchi come `/dev/nvme0n1` e le sue partizioni. (Un fratello `devb-virtio` guida il dispositivo QEMU virtio-blk per il target emulato.)
- **`fs-qrv`** — il resource manager del filesystem. Monta una partizione e serve il namespace del filesystem POSIX tramite passaggio di messaggi: le chiamate `open`/`read`/`write`/`close` di un'applicazione diventano messaggi a cui `fs-qrv` risponde.
Un tipico avvio monta una partizione NVMe reale e vi esegue programmi:```
mount -t qrv /dev/nvme0n1p5 /disk2
Questo percorso — driver di blocco, partizionamento, server del filesystem e il kernel che media ogni messaggio tra di loro — funziona end-to-end sia su QEMU che sul drive NVMe della SiFive Unmatched.
QRV si avvia tramite sysinit/init, avvia il driver della console seriale
(devc-ser8250 su QEMU, devc-sersifive su FU740), il server PCI, lo
stack di archiviazione, e getty/login, e ti porta a un prompt della shell. I
programmi principali nello spazio utente:
sh — mksh, la shell Korn MirBSD. Una vera shell POSIX scriptabile
è la shell di sistema; gli script di avvio (level1.sh, …) sono normali
script shell.pidin — il classico strumento "process info" di QNX: elenca processi,
thread, i loro stati, memoria, e altro ancora. È la sonda principale di QRV per
"il sistema è vivo e funzionante?" e il suo carico di lavoro standard per stress test.lspci — enumera il bus PCI/PCIe attraverso il server PCI.sloginfo — scarica il log di sistema raccolto dal server slogger.Accanto a questi ci sono gli elementi costitutivi di un sistema multiutente utilizzabile:
getty e login (con supporto per credenziali/auth), mount, shutdown,
pipe, e utilità essenziali (ls, cat, …). Ogni programma QRV è
multi-thread — almeno un thread principale e un thread di sistema — che è
esattamente il motivo per cui la corretta sincronizzazione SMP (vedere §6)
è così importante.
Cross-compiler : riscv64-linux-gnu-gcc CPU flags : -march=rv64g -mcmodel=medany -mno-relax Build style : -nostdinc -nostdlib -ffreestanding
### Comandi comuni (esegui all'interno di `os/`)```bash
make # Build everything: startup + kernel + module package
make -Bj # Force a full parallel rebuild (do this after header changes)
make startup # Build startup only
make kernel # Build kernel only
make modpkg # Create the module package (CPIO)
make qemu # Build and run in QEMU
./emu.sh # Run in QEMU (4 CPUs, 256M RAM, virt machine)
./emu.sh -P 1 # Run with a single hart
./emu.sh -gdb # Run with the GDB remote stub (port 1234)
La piattaforma di test principale è qemu-system-riscv64 sulla macchina virt. La configurazione è basata su Kconfig.
L'obiettivo secondario ma serio di QRV è la SiFive Unmatched (FU740) — una vera scheda workstation RISC-V. Far sì che un microkernel che si avvia correttamente su QEMU si avvii anche correttamente su silicio fisico ha portato alla luce una classe di bug che l'emulazione semplicemente non presenta, e inseguirli è gran parte di ciò di cui parlano le release recenti.
L'esempio emblematico, risolto nella v0.43: per due mesi QRV funzionava perfettamente su QEMU e si bloccava sull'hardware reale. Sulla FU740, qualsiasi programma — pidin, lspci, qualsiasi — crashava dopo una manciata di spawn, ogni crash diverso dal precedente, il program counter che vagava in dati spazzatura. La causa non era affatto una corruzione della memoria, ma incoerenza della cache delle istruzioni: RISC-V non garantisce alcuna coerenza tra i salvataggi dei dati e il fetch delle istruzioni, quindi il codice del programma appena caricato è invisibile all'unità di fetch di un hart finché quell'hart non esegue fence.i — e il codice che verrà eseguito su un hart diverso da quello che lo ha caricato necessita di un fence.i remoto lì. Il loader di QRV non faceva nessuno dei due (aveva persino calcolato un flag "invalida cache I" e poi lo scartava). QEMU non modella alcuna cache di istruzioni, quindi il bug era invisibile lì e deterministico sulla U74.
La soluzione — un fence.i locale più una trasmissione SBI (cpu_icache_sync_all()) in ogni punto in cui una pagina diventa eseguibile — ha trasformato un ciclo di spawn che falliva ogni poche esecuzioni in uno che è arrivato oltre 600 spawn consecutivi senza errori sulla FU740. L'indagine completa, inclusa l'ipotesi sbagliata iniziale e la diagnostica che l'ha ribaltata, è la sezione conclusiva del capitolo 14 di The QRV Porting Story.
I traguardi hardware raggiunti finora includono l'avvio fino a un prompt login: in taskman in modalità utente sulla FU740, e il montaggio e l'esecuzione di programmi di test da una partizione NVMe reale.
QNX è uno dei progetti di microkernel più influenti mai distribuiti. Il suo modello send/receive/reply ha insegnato a generazioni di ingegneri di sistema come può essere un'architettura OS pulita. Eppure il codice che lo incarna ha trascorso più di un decennio in un limbo peculiare: abbastanza visibile per essere studiato sotto una licenza comunitaria, ma non abbastanza libero da essere ridistribuito, evoluto o per costruirci un ecosistema vivo. Un design così buono merita di meglio che essere preservato solo come un artefatto di sola lettura.
Questo è il motivo per cui questo lavoro esiste. QRV è, francamente, un veicolo di transizione — un modo per imparare l'architettura in profondità portandola, smontandola e rimontandola su nuovo hardware, rimuovendo il lock del kernel e portando il gestore dei processi nello spazio utente e scoprendo esattamente quali assunzioni erano portanti. Ogni bug inseguito su silicio reale, ogni sottosistema riscritto per essere pulito a 64 bit, ogni confine proprietario smantellato, è conoscenza di cui un'implementazione veramente libera avrà bisogno.
Perché l'obiettivo a lungo termine non è mantenere per sempre una copia patchata dei sorgenti di qualcun altro. È un sistema operativo completamente libero, scritto da zero, compatibile con le interfacce di QNX e fedele alla sua filosofia di microkernel, ma che non deve nulla al codice proprietario — uno che possa essere usato, insegnato, distribuito e migliorato senza chiedere il permesso a nessuno. QRV è il modo in cui dimostriamo che un tale sistema non è solo possibile ma pratico, e come otteniamo l'esperienza per costruirlo correttamente.
Se desideri che le stesse fondamenta storiche diventino libere, aggiungi il tuo nome a PETITION.md. E se vuoi vedere come è fatto un microkernel moderno e onestamente ingegnerizzato dall'interno — clona il recipe, esegui obtain_proj.sh, e leggi il codice.
QRV — adattamento e re-implementazione di QNX Neutrino 6.4 per hardware a 64 bit. Iniziato la Vigilia di Natale 2020. Apache 2.0 (codice proprio di QRV) + BlackBerry QCL 2.0 (sorgenti derivati da QNX). Vedi WHAT_IS_WHAT.md per la suddivisione componente per componente.
| File / dir | Scopo |
|---|
obtain_proj.sh | Lo script di ricostruzione — esegui questo. |
placement.txt | Mappa ogni path QNX upstream al suo path QRV (≈680 voci). |
patches/ | La serie di patch QRV, compresse con LZ4, più un file di ordinamento series. |
LICENSE.txt | Licenza Apache 2.0. |
WHAT_IS_WHAT.md | Licenze e provenienza componente per componente. |
PETITION.md | La petizione per il cambio di licenza. |