Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 13 additions & 1 deletion mk/20-build.mk
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
# STARK attestation for the kernel and every capsule. This is where make,
# make qemu, and make from-config all resolve their real work.

.PHONY: nonos-mk-check-driver-ahci-keys nonos-mk-check-driver-e1000-keys nonos-mk-check-driver-hda-keys nonos-mk-check-driver-i2c-hid-keys nonos-mk-check-driver-i2c-pci-keys nonos-mk-check-driver-iwlwifi-keys nonos-mk-check-driver-nvme-keys nonos-mk-check-driver-rtl8139-keys nonos-mk-check-driver-rtl8169-keys nonos-mk-check-driver-rtl8821ce-keys nonos-mk-check-driver-usb-msc-keys nonos-mk-check-driver-virtio-gpu-keys nonos-mk-check-ps2-input-keys nonos-mk-check-ramfs-keys nonos-mk-check-virtio-blk-keys nonos-mk-check-virtio-net-keys nonos-mk-check-virtio-rng-keys nonos-mk-check-xhci-keys nonos-mk-crypto nonos-mk-driver-ahci nonos-mk-driver-ahci-sign nonos-mk-driver-e1000 nonos-mk-driver-e1000-sign nonos-mk-driver-hda nonos-mk-driver-hda-sign nonos-mk-driver-i2c-hid nonos-mk-driver-i2c-hid-sign nonos-mk-driver-i2c-pci nonos-mk-driver-i2c-pci-sign nonos-mk-driver-iwlwifi nonos-mk-driver-iwlwifi-sign nonos-mk-driver-nvme nonos-mk-driver-nvme-sign nonos-mk-driver-rtl8139 nonos-mk-driver-rtl8139-sign nonos-mk-driver-rtl8169 nonos-mk-driver-rtl8169-sign nonos-mk-driver-rtl8821ce nonos-mk-driver-rtl8821ce-sign nonos-mk-driver-usb-msc nonos-mk-driver-usb-msc-sign nonos-mk-driver-virtio-gpu nonos-mk-driver-virtio-gpu-sign nonos-mk-entropy nonos-mk-keyring nonos-mk-market nonos-mk-proof-io nonos-mk-proof-io-sign nonos-mk-ps2-input nonos-mk-ps2-input-sign nonos-mk-ramfs nonos-mk-ramfs-sign nonos-mk-vfs nonos-mk-virtio-blk nonos-mk-virtio-blk-sign nonos-mk-virtio-net nonos-mk-virtio-net-sign nonos-mk-virtio-rng nonos-mk-virtio-rng-sign nonos-mk-wallpaper nonos-mk-xhci nonos-mk-xhci-sign nonos-mk-all-capsules-attested nonos-mk-attest nonos-mk-attestation nonos-mk-attestation-receipt nonos-mk-bootloader nonos-mk-capsules nonos-mk-check nonos-mk-check-trust-keys nonos-mk-check-trust-manifest nonos-mk-core nonos-mk-core-attested nonos-mk-desktop-gui-prod nonos-mk-smp-prod nonos-mk-ensure-zk-keys nonos-mk-esp nonos-mk-from-config nonos-mk-host-trust-verify nonos-mk-libc nonos-mk-live-production-proof nonos-mk-marketplace-abi nonos-mk-marketplace-index-tool nonos-mk-menuconfig nonos-mk-sign nonos-mk-terminal-test nonos-mk-trust-policy nonos-mk-usb-img nonos-mk-userland-clean nonos-mk-verify-capsule-attest nonos-mk-verify-trust nonos-mk-zerostate nonos-mk-zk-report nonos-mk-zk-tools nonos-mk-zk-verify-live
.PHONY: nonos-mk-check-driver-ahci-keys nonos-mk-check-driver-e1000-keys nonos-mk-check-driver-hda-keys nonos-mk-check-driver-i2c-hid-keys nonos-mk-check-driver-i2c-pci-keys nonos-mk-check-driver-iwlwifi-keys nonos-mk-check-driver-nvme-keys nonos-mk-check-driver-rtl8139-keys nonos-mk-check-driver-rtl8169-keys nonos-mk-check-driver-rtl8821ce-keys nonos-mk-check-driver-usb-msc-keys nonos-mk-check-driver-virtio-gpu-keys nonos-mk-check-ps2-input-keys nonos-mk-check-ramfs-keys nonos-mk-check-virtio-blk-keys nonos-mk-check-virtio-net-keys nonos-mk-check-virtio-rng-keys nonos-mk-check-xhci-keys nonos-mk-crypto nonos-mk-driver-ahci nonos-mk-driver-ahci-sign nonos-mk-driver-e1000 nonos-mk-driver-e1000-sign nonos-mk-driver-hda nonos-mk-driver-hda-sign nonos-mk-driver-i2c-hid nonos-mk-driver-i2c-hid-sign nonos-mk-driver-i2c-pci nonos-mk-driver-i2c-pci-sign nonos-mk-driver-iwlwifi nonos-mk-driver-iwlwifi-sign nonos-mk-driver-nvme nonos-mk-driver-nvme-sign nonos-mk-driver-rtl8139 nonos-mk-driver-rtl8139-sign nonos-mk-driver-rtl8169 nonos-mk-driver-rtl8169-sign nonos-mk-driver-rtl8821ce nonos-mk-driver-rtl8821ce-sign nonos-mk-driver-usb-msc nonos-mk-driver-usb-msc-sign nonos-mk-driver-virtio-gpu nonos-mk-driver-virtio-gpu-sign nonos-mk-entropy nonos-mk-keyring nonos-mk-market nonos-mk-proof-io nonos-mk-proof-io-sign nonos-mk-ps2-input nonos-mk-ps2-input-sign nonos-mk-ramfs nonos-mk-ramfs-sign nonos-mk-vfs nonos-mk-virtio-blk nonos-mk-virtio-blk-sign nonos-mk-virtio-net nonos-mk-virtio-net-sign nonos-mk-virtio-rng nonos-mk-virtio-rng-sign nonos-mk-wallpaper nonos-mk-xhci nonos-mk-xhci-sign nonos-mk-all-capsules-attested nonos-mk-attest nonos-mk-attestation nonos-mk-attestation-receipt nonos-mk-bootloader nonos-mk-capsules nonos-mk-check nonos-mk-check-trust-keys nonos-mk-check-trust-manifest nonos-mk-core nonos-mk-core-attested nonos-mk-desktop-gui-prod nonos-mk-smp-prod nonos-mk-ethernet-prod nonos-mk-ensure-zk-keys nonos-mk-esp nonos-mk-from-config nonos-mk-host-trust-verify nonos-mk-libc nonos-mk-live-production-proof nonos-mk-marketplace-abi nonos-mk-marketplace-index-tool nonos-mk-menuconfig nonos-mk-sign nonos-mk-terminal-test nonos-mk-trust-policy nonos-mk-usb-img nonos-mk-userland-clean nonos-mk-verify-capsule-attest nonos-mk-verify-trust nonos-mk-zerostate nonos-mk-zk-report nonos-mk-zk-tools nonos-mk-zk-verify-live

# ZK attestation: transparent enrolled-secret tools

Expand Down Expand Up @@ -1179,6 +1179,18 @@ nonos-mk-install-prod: $(DESKTOP_GUI_CAPSULE_ARTIFACTS) $(driver-nvme_ARTIFACTS)
nonos-mk-check-deps nonos-mk-ensure-signing-key
$(call nonos_kernel_build,microkernel-desktop-gui + nvme + install,microkernel-desktop-gui$(_boot_comma)nonos-stark-attest$(_boot_comma)nonos-capsule-driver-nvme)

# nonos-mk-ethernet-prod: the desktop profile with the wired NIC drivers in it.
# QEMU models the e1000 and the RTL8139, so each boots against its own device
# and has to take a lease through it; the RTL8169 has no QEMU model and is here
# to show a driver whose chip is absent exits and lets the boot go on.
ETHERNET_DRIVER_ARTIFACTS := $(driver-e1000_ARTIFACTS) $(driver-rtl8139_ARTIFACTS) \
$(driver-rtl8169_ARTIFACTS)

nonos-mk-ethernet-prod: $(DESKTOP_GUI_CAPSULE_ARTIFACTS) $(ETHERNET_DRIVER_ARTIFACTS) \
nonos-mk-verify-desktop-gui-capsules \
nonos-mk-check-deps nonos-mk-ensure-signing-key
$(call nonos_kernel_build,microkernel-desktop-gui + wired NICs,microkernel-desktop-gui$(_boot_comma)nonos-stark-attest$(_boot_comma)nonos-capsule-driver-e1000$(_boot_comma)nonos-capsule-driver-rtl8139$(_boot_comma)nonos-capsule-driver-rtl8169)

# nonos-mk-smp-prod: the desktop profile with the secondary CPUs turned on.
# Same capsule set and the same attestation, so a difference between this boot
# and the single-CPU one is the AP bring-up and nothing else.
Expand Down
5 changes: 2 additions & 3 deletions src/hardware/e1000_capsule/spawn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! Spawn the e1000 driver capsule with the broker capability
//! bundle. PCI MMIO + INTx + DMA driver — needs IPC | Memory |
//! Driver | DeviceEnum | Mmio | Irq | Dma. No Network cap: frame
//! bundle. PCI MMIO + DMA driver, polled — needs IPC | Memory |
//! Crypto | Driver | DeviceEnum | Mmio | Dma. No Network cap: frame
//! transport over IPC, not a network-service authority.

use super::client::REPLY_INBOX;
Expand Down Expand Up @@ -62,7 +62,6 @@ pub fn spawn_driver_e1000_capsule() -> Result<(), SpawnError> {
| Capability::Driver.bit()
| Capability::DeviceEnum.bit()
| Capability::Mmio.bit()
| Capability::Irq.bit()
| Capability::Dma.bit(),
debug_tag: b"[DRIVER-E1000] load_elf_executable error:",
};
Expand Down
5 changes: 4 additions & 1 deletion src/hardware/rtl8139_capsule/spawn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,12 @@ pub fn spawn_driver_rtl8139_capsule() -> Result<(), SpawnError> {
target_triple: TARGET_TRIPLE,
requested_caps: Capability::IPC.bit()
| Capability::Memory.bit()
// The station address is drawn rather than read out of the IDR,
// and CryptoRandom is gated on this capability. The draw fails
// closed, so without it the card never comes up.
| Capability::Crypto.bit()
| Capability::Driver.bit()
| Capability::DeviceEnum.bit()
| Capability::Irq.bit()
| Capability::Dma.bit()
| Capability::Pio.bit(),
debug_tag: b"[DRIVER-RTL8139] load_elf_executable error:",
Expand Down
5 changes: 4 additions & 1 deletion src/hardware/rtl8169_capsule/spawn.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,13 @@ pub fn spawn_driver_rtl8169_capsule() -> Result<(), SpawnError> {
target_triple: TARGET_TRIPLE,
requested_caps: Capability::IPC.bit()
| Capability::Memory.bit()
// The station address is drawn rather than read out of the IDR,
// and CryptoRandom is gated on this capability. The draw fails
// closed, so without it the card never comes up.
| Capability::Crypto.bit()
| Capability::Driver.bit()
| Capability::DeviceEnum.bit()
| Capability::Mmio.bit()
| Capability::Irq.bit()
| Capability::Dma.bit(),
debug_tag: b"[DRIVER-RTL8169] load_elf_executable error:",
};
Expand Down
7 changes: 4 additions & 3 deletions userland/capsule_driver_e1000/Capsule.mk
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# e1000 — Intel 8254x gigabit NIC. PCI MMIO + INTx + DMA with
# e1000 — Intel 8254x gigabit NIC. PCI MMIO + DMA, polled, with
# separate RX and TX rings (four DMA grants total). Frame-level
# transport over IPC; no socket or routing policy. `Network` cap
# is intentionally absent — that authority belongs to a future
Expand All @@ -15,11 +15,12 @@ CAPSULE_FEATURE := nonos-capsule-driver-e1000
CAPSULE_NAMESPACE := systems.nonos.driver.e1000_0
CAPSULE_SERVICE_ENDPOINT := service:4210:driver.e1000_0
CAPSULE_REPLY_ENDPOINT := reply:4211:endpoint.4294967308
# IPC|Memory|Crypto|Driver|DeviceEnum|Mmio|Irq|Dma = 0xF8039
# IPC|Memory|Crypto|Driver|DeviceEnum|Mmio|Dma = 0xB8039. No Irq: the driver
# polls and binds no line.
# Crypto (0x20) is what the CryptoRandom syscall is gated on. The station address
# is drawn rather than read out of the EEPROM, and that draw fails closed, so
# without this the card has no address to transmit under.
CAPSULE_REQUIRED_CAPS := 0xF8039
CAPSULE_REQUIRED_CAPS := 0xB8039
CAPSULE_KERNEL_MIRROR := src/hardware/e1000_capsule

include nonos-mk/capsule.mk
5 changes: 4 additions & 1 deletion userland/capsule_driver_e1000/src/constants/frame.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,8 @@ const ETH_HEADER_LEN: usize = 14;
const MTU: usize = 1500;

pub const MAC_LEN: usize = 6;
pub const MIN_ETHERNET_FRAME: usize = 60;
/// A bare header is the shortest frame taken. TCTL.PSP has the part pad
/// anything under 60 bytes, and an ARP (42) or a bare TCP ACK (54) is shorter
/// than that: refusing them stranded IPv4 right after DHCP.
pub const MIN_ETHERNET_FRAME: usize = ETH_HEADER_LEN;
pub const MAX_ETHERNET_FRAME: usize = MTU + ETH_HEADER_LEN;
8 changes: 5 additions & 3 deletions userland/capsule_driver_e1000/src/discover.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ const PCI_SUBCLASS_ETHERNET: u8 = 0x00;
#[derive(Clone, Copy)]
pub struct Found {
pub device_id: u64,
pub irq_line: u8,
pub bar0_size: u64,
}

Expand All @@ -40,14 +39,17 @@ pub fn find_e1000() -> Option<Found> {
if !is_match(r) {
continue;
}
if r.irq_pin == 0 || r.irq_line == 0xFF || r.bar_count == 0 {
// Interrupt routing is not asked for: the driver polls. UEFI firmware
// often leaves Interrupt Line at 0xFF, and filtering on it skipped a
// working NIC on exactly the machines this driver is for.
if r.bar_count == 0 {
continue;
}
let bar0 = r.bars[0];
if bar0.kind != BAR_KIND_MMIO || bar0.size == 0 {
continue;
}
return Some(Found { device_id: r.device_id, irq_line: r.irq_line, bar0_size: bar0.size });
return Some(Found { device_id: r.device_id, bar0_size: bar0.size });
}
None
}
Expand Down
60 changes: 48 additions & 12 deletions userland/capsule_driver_e1000/src/init/reset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,34 +14,61 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

//! Hardware reset + IRQ quiesce + link bring-up. CTRL.RST is
//! self-clearing; the loop bound is generous because the device
//! takes a few microseconds to settle. After reset the firmware
//! restores most defaults but leaves all IMS bits set, so the
//! capsule masks every cause through IMC and reads ICR to clear
//! any latched bits before enabling the link.

use crate::constants::regs::{REG_CTRL, REG_ICR, REG_IMC};
//! Hardware reset + IRQ quiesce + link bring-up, in the order the 8254x
//! needs on silicon:
//!
//! 1. Mask every cause and stop both DMA engines, then give bus-master
//! cycles already in flight time to drain. Firmware (PXE, UEFI UNDI) or a
//! previous instance can leave RCTL.EN set, and a reset landing mid-DMA
//! is a known hang on PCI-X parts.
//! 2. Set CTRL.RST and poll for it to self-clear, reading nothing in the
//! first microsecond the manual says the part is unreachable.
//! 3. Wait out the EEPROM auto-load the reset starts. It rewrites RAL0/RAH0
//! and parts of CTRL, so a MAC or SLU written before it finishes can be
//! put back to the factory value: unicast then goes to the wrong filter.
//! 4. Mask again, clear latched causes, and bring the link up.

use nonos_libc::Deadline;

use crate::constants::regs::{REG_CTRL, REG_ICR, REG_IMC, REG_RCTL, REG_STATUS, REG_TCTL};
use crate::constants::status::{CTRL_ASDE, CTRL_LRST, CTRL_RST, CTRL_SLU};
use crate::regs::Regs;

const RESET_POLL_BUDGET: u32 = 100_000;
/// Linux e1000_reset_hw's drain before the reset.
const DMA_DRAIN_MS: u64 = 10;
/// The part is not addressable for about a microsecond after RST is set.
const RST_SETTLE_MS: u64 = 1;
/// Bound on RST self-clearing; it takes microseconds on a working part.
const RST_CLEAR_MS: u64 = 50;
/// EEPROM auto-load after a global reset: 5 ms on 82540/82545/82546,
/// 20 ms on 82541/82547, so the longer one covers every listed part.
const EEPROM_RELOAD_MS: u64 = 20;

pub fn run(regs: &Regs) -> Result<(), &'static str> {
// SAFETY: eK@nonos.systems — `regs` carries a base from a
// valid broker MmioMap grant; offsets are 32-bit aligned per
// the 8254x manual.
unsafe {
// Both engines off. Nothing else is set here: a card that never gets a
// station address is left with neither enable bit ever written.
regs.w32(REG_IMC, 0xFFFF_FFFF);
regs.w32(REG_RCTL, 0);
regs.w32(REG_TCTL, 0);
let _ = regs.r32(REG_STATUS);
hold_ms(DMA_DRAIN_MS);

let ctrl = regs.r32(REG_CTRL);
regs.w32(REG_CTRL, ctrl | CTRL_RST);
let mut spins = 0u32;
hold_ms(RST_SETTLE_MS);
let deadline = Deadline::after_ms(RST_CLEAR_MS);
while regs.r32(REG_CTRL) & CTRL_RST != 0 {
spins += 1;
if spins > RESET_POLL_BUDGET {
if deadline.expired() {
return Err("CTRL.RST did not self-clear");
}
core::hint::spin_loop();
}
hold_ms(EEPROM_RELOAD_MS);

regs.w32(REG_IMC, 0xFFFF_FFFF);
let _ = regs.r32(REG_ICR);
let mut ctrl = regs.r32(REG_CTRL);
Expand All @@ -51,3 +78,12 @@ pub fn run(regs: &Regs) -> Result<(), &'static str> {
}
Ok(())
}

// At least `ms` milliseconds: uptime counts whole milliseconds, so a deadline
// `ms` ahead can fall due up to one early.
fn hold_ms(ms: u64) {
let until = Deadline::after_ms(ms + 1);
while !until.expired() {
core::hint::spin_loop();
}
}
4 changes: 4 additions & 0 deletions userland/capsule_driver_e1000/src/init/rx_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
//! and finally enables the receiver via RCTL. RDT points at the
//! last valid descriptor index per the 8254x manual.

use core::sync::atomic::{fence, Ordering};

use crate::constants::queue::{RX_DESC_COUNT, RX_RING_BYTES};
use crate::constants::regs::{REG_RCTL, REG_RDBAH, REG_RDBAL, REG_RDH, REG_RDLEN, REG_RDT};
use crate::constants::status::{RCTL_BAM, RCTL_BSIZE_2048, RCTL_EN, RCTL_SECRC};
Expand All @@ -37,6 +39,8 @@ pub fn program(regs: &Regs, rx: &RxRing, ring_phys: u64) {
*d = RxDesc::default();
d.buffer_addr = rx.buffer_phys(i as u16);
}
// The ring was written with plain stores; the part reads it from here on.
fence(Ordering::Release);
regs.w32(REG_RDBAL, (ring_phys & 0xFFFF_FFFF) as u32);
regs.w32(REG_RDBAH, (ring_phys >> 32) as u32);
regs.w32(REG_RDLEN, RX_RING_BYTES as u32);
Expand Down
4 changes: 4 additions & 0 deletions userland/capsule_driver_e1000/src/init/tx_setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
//! (`0x00602008`), and enables the transmitter via TCTL with the
//! pad-short-packet bit and a 16-retry collision threshold.

use core::sync::atomic::{fence, Ordering};

use crate::constants::queue::{TX_DESC_COUNT, TX_RING_BYTES};
use crate::constants::regs::{
REG_TCTL, REG_TDBAH, REG_TDBAL, REG_TDH, REG_TDLEN, REG_TDT, REG_TIPG,
Expand All @@ -39,6 +41,8 @@ pub fn program(regs: &Regs, tx: &TxRing, ring_phys: u64) {
for i in 0..TX_DESC_COUNT {
*descs.add(i) = TxDesc::default();
}
// The ring was written with plain stores; the part reads it from here on.
fence(Ordering::Release);
regs.w32(REG_TDBAL, (ring_phys & 0xFFFF_FFFF) as u32);
regs.w32(REG_TDBAH, (ring_phys >> 32) as u32);
regs.w32(REG_TDLEN, TX_RING_BYTES as u32);
Expand Down
22 changes: 0 additions & 22 deletions userland/capsule_driver_e1000/src/protocol/endpoint.rs

This file was deleted.

5 changes: 4 additions & 1 deletion userland/capsule_driver_e1000/src/protocol/header.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

pub const MAGIC: u32 = 0x4E45_3130;
/// "NNET", the NIC protocol net_core and net_l2 speak (virtio-net's too).
/// The per-driver tag this replaced made every request from the stack
/// undecodable, so the wired NICs never served it.
pub const MAGIC: u32 = 0x4E4E_4554;
pub const VERSION: u16 = 1;

pub const HDR_LEN: usize = 20;
Expand Down
2 changes: 0 additions & 2 deletions userland/capsule_driver_e1000/src/protocol/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,13 @@

mod decode;
mod encode;
mod endpoint;
mod errno;
mod header;
mod limits;
mod ops;

pub use decode::decode_request;
pub use encode::{encode_response_header, write_status};
pub use endpoint::KERNEL_REPLY_ENDPOINT;
pub use errno::{E_AGAIN, E_INVAL, E_IO, E_MSGSIZE};
pub use header::{Request, HDR_LEN, RESP_HDR_LEN};
pub use limits::{
Expand Down
4 changes: 4 additions & 0 deletions userland/capsule_driver_e1000/src/queue/rx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.

use core::sync::atomic::{fence, Ordering};

use crate::constants::queue::{RX_BUFFER_LEN, RX_DESC_COUNT, RX_STATUS_DD, RX_STATUS_EOP};
use crate::constants::MAX_ETHERNET_FRAME;

Expand Down Expand Up @@ -60,6 +62,8 @@ impl RxRing {
if status & RX_STATUS_DD == 0 {
return None;
}
// Length, errors and the frame are only the part's once DD is seen.
fence(Ordering::Acquire);
let errors = unsafe { read_volatile(addr_of!((*desc).errors)) };
let len = unsafe { read_volatile(addr_of!((*desc).length)) };
let idx = self.head;
Expand Down
Loading
Loading