Repository navigation
toyos-acpi decodes the IORT; toyos-smmu and toyos-its hold the SMMUv3's and the ITS's encodings, over toyos-phys's one address type - #798
Conversation
…u and toyos-its hold the SMMUv3's and the ITS's encodings Stage G1 of the ARM desktop: host-only, no kernel file. The kernel's SMMUv3 unit (G2) and its ITS (G3) are built on these. toyos-acpi: `iort` answers an IORT every node of which it walked, with the SMMUv3 node's base and four GSIVs, the ITS node's id, and `route(segment, rid)`: through which SMMUv3 under which StreamID and on to which ITS under which DeviceID, straight to an ITS past every SMMU, or mapped nowhere. The refusals are by name: a table or node revision not read against DEN 0049, a node the table cannot hold, an ID array over its node's fields or past its end, a range past the ID space, an output reference to no node or to one its source may not reach, a root complex single mapping, an ITS group of other than one, and an ID two mappings claim. `msi_controllers` walks the MADT for its ITS and GIC MSI Frame structures; the frame is not a `MadtEntry` variant because the kernel matches that enum exhaustively in two files this stage does not touch. The fixtures are QEMU 11.1.1 `virt`'s RSDP, XSDT, MADT and IORT in both GIC modes, captured with the firmware alone in the guest (`SOURCE` beside them). toyos-smmu: the identification registers judged (`probe`), the stream table entry that aborts and the one that translates by stage 1 through one context descriptor, the context descriptor, the register values, the queue index arithmetic, the commands, the event records, and the stage 1 table plan with its 2 MiB memory block and its one 4 KiB doorbell page. No bypass is spelled. toyos-its: the type register judged, the table and command queue registers, the commands, and the LPI configuration and pending tables with the redistributor registers that name them. The device and translation table entries are IMPLEMENTATION DEFINED and the ITS's own, so only their sizes are here. Every encoding is tested against the specification's field positions (IHI 0070 H.a, IHI 0069 H.b, DDI 0487 M.d, ACPI 6.5), written in the tests as `(msb, lsb, value)` triples and compared whole. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Mutations of The patches# iort-table-revision
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -177,7 +177,7 @@
let table = find_table(phys, rsdp_addr, b"IORT", IORT_NEEDED)?;
let short = TableError::Length { declared: table.len() as u32, needed: IORT_NEEDED };
let revision = table.byte(SDT_REVISION).ok_or(short)?;
- if !REVISIONS.contains(&revision) {
+ if false {
return Err(IortRefused::Revision(revision));
}
let nodes = table.u32_at(NODE_COUNT).ok_or(short)?;
# iort-node-array-floor
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -182,7 +182,7 @@
}
let nodes = table.u32_at(NODE_COUNT).ok_or(short)?;
let offset = table.u32_at(NODE_ARRAY).ok_or(short)?;
- if (offset as usize) < IORT_NEEDED {
+ if false {
return Err(IortRefused::NodeArray { offset });
}
let iort = Iort { table, nodes, array: offset as usize };
# iort-node-past-table
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -271,7 +271,7 @@
SMMUV3 => SMMU_LEN,
_ => NODE_HEADER,
};
- if len < floor || at + len > t.len() {
+ if len < floor {
return Err(IortRefused::Node { at, declared: len });
}
Ok(Raw { at, kind, len, revision, mappings, array })
# iort-node-too-short
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -271,7 +271,7 @@
SMMUV3 => SMMU_LEN,
_ => NODE_HEADER,
};
- if len < floor || at + len > t.len() {
+ if at + len > t.len() {
return Err(IortRefused::Node { at, declared: len });
}
Ok(Raw { at, kind, len, revision, mappings, array })
# iort-node-revision
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -327,7 +327,7 @@
Node::RootComplex { segment: t.u32_at(at + RC_SEGMENT).ok_or(short)? }
}
SMMUV3 => {
- revised(4..=5)?;
+ revised(0..=255)?;
let gsiv = |i: usize| t.u32_at(at + SMMU_GSIVS + 4 * i).map(NonZeroU32::new).ok_or(short);
Node::Smmuv3(Smmuv3 {
base: t.u64_at(at + SMMU_BASE).ok_or(short)?,
# iort-root-revision
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -323,7 +323,7 @@
Node::Its { id: t.u32_at(at + NODE_HEADER + 4).ok_or(short)? }
}
ROOT_COMPLEX => {
- revised(3..=4)?;
+ revised(0..=255)?;
Node::RootComplex { segment: t.u32_at(at + RC_SEGMENT).ok_or(short)? }
}
SMMUV3 => {
# iort-its-revision
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -315,7 +315,7 @@
};
Ok(match kind {
ITS => {
- revised(1..=1)?;
+ revised(0..=255)?;
let count = t.u32_at(at + NODE_HEADER).ok_or(short)?;
if count != 1 {
return Err(IortRefused::ItsGroup { at, count });
# iort-array-over-fields
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -355,7 +355,7 @@
};
let Raw { at, mappings: count, array: offset, .. } = raw;
let end = u64::from(offset) + u64::from(count) * MAPPING as u64;
- let misplaced = (offset as usize) < fields || end > raw.len as u64;
+ let misplaced = end > raw.len as u64;
if count != 0 && (misplaced || matches!(node, Node::Its { .. })) {
return Err(IortRefused::Mappings { at, count, offset });
}
# iort-root-rev4-fields
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -350,7 +350,7 @@
(Node::Other(_), _) => return Ok(()),
(Node::Its { .. }, _) => ITS_LEN,
(Node::RootComplex { .. }, 3) => 36,
- (Node::RootComplex { .. }, _) => 40,
+ (Node::RootComplex { .. }, _) => 36,
(Node::Smmuv3(_), _) => SMMU_LEN,
};
let Raw { at, mappings: count, array: offset, .. } = raw;
# iort-array-past-node
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -355,7 +355,7 @@
};
let Raw { at, mappings: count, array: offset, .. } = raw;
let end = u64::from(offset) + u64::from(count) * MAPPING as u64;
- let misplaced = (offset as usize) < fields || end > raw.len as u64;
+ let misplaced = (offset as usize) < fields;
if count != 0 && (misplaced || matches!(node, Node::Its { .. })) {
return Err(IortRefused::Mappings { at, count, offset });
}
# iort-its-with-array
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -356,7 +356,7 @@
let Raw { at, mappings: count, array: offset, .. } = raw;
let end = u64::from(offset) + u64::from(count) * MAPPING as u64;
let misplaced = (offset as usize) < fields || end > raw.len as u64;
- if count != 0 && (misplaced || matches!(node, Node::Its { .. })) {
+ if count != 0 && (misplaced) {
return Err(IortRefused::Mappings { at, count, offset });
}
for index in 0..count {
# iort-range-wraps
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -367,7 +367,7 @@
}
if !mapping.single {
for base in [mapping.input, mapping.output] {
- if base.checked_add(mapping.span).is_none() {
+ if false {
return Err(IortRefused::Range { at, base, last: mapping.span });
}
}
# iort-smmu-to-smmu
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -374,7 +374,7 @@
}
match self.output(raw, mapping)?.1 {
Node::Its { .. } => {}
- Node::Smmuv3(_) if from_root => {}
+ Node::Smmuv3(_) => {}
_ => return Err(IortRefused::Output { at, reference: mapping.reference }),
}
}
# iort-output-any-kind
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -375,7 +375,7 @@
match self.output(raw, mapping)?.1 {
Node::Its { .. } => {}
Node::Smmuv3(_) if from_root => {}
- _ => return Err(IortRefused::Output { at, reference: mapping.reference }),
+ _ => {}
}
}
Ok(())
# iort-output-mid-node
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -295,7 +295,7 @@
let refused = IortRefused::Output { at: from.at, reference: mapping.reference };
for raw in self.raw_nodes() {
let raw = raw?;
- if raw.at == mapping.reference as usize {
+ if raw.at <= mapping.reference as usize && raw.at + raw.len > mapping.reference as usize {
return Ok((raw, self.decode(raw)?));
}
}
# iort-root-single
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -362,7 +362,7 @@
for index in 0..count {
let mapping = self.mapping(raw, index).ok_or(IortRefused::Mappings { at, count, offset })?;
let from_root = matches!(node, Node::RootComplex { .. });
- if mapping.single && from_root {
+ if false {
return Err(IortRefused::SingleMapping { at });
}
if !mapping.single {
# iort-single-routes
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -160,7 +160,7 @@
impl Mapping {
fn maps(&self, id: u32) -> Option<u32> {
// `output + span` was checked not to wrap when the table was opened.
- (!self.single && id >= self.input && id - self.input <= self.span).then(|| self.output + (id - self.input))
+ (id >= self.input && id - self.input <= self.span).then(|| self.output + (id - self.input))
}
}
# iort-single-range-judged
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -365,7 +365,7 @@
if mapping.single && from_root {
return Err(IortRefused::SingleMapping { at });
}
- if !mapping.single {
+ if true {
for base in [mapping.input, mapping.output] {
if base.checked_add(mapping.span).is_none() {
return Err(IortRefused::Range { at, base, last: mapping.span });
# iort-its-group
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -317,7 +317,7 @@
ITS => {
revised(1..=1)?;
let count = t.u32_at(at + NODE_HEADER).ok_or(short)?;
- if count != 1 {
+ if false {
return Err(IortRefused::ItsGroup { at, count });
}
Node::Its { id: t.u32_at(at + NODE_HEADER + 4).ok_or(short)? }
# iort-overlap-root
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -224,7 +224,7 @@
}
_ => return Err(IortRefused::Output { at: raw.at, reference: mapping.reference }),
};
- if route.replace(hop).is_some() {
+ if route.replace(hop).is_some() && false {
return Err(IortRefused::Overlap { id: u32::from(rid) });
}
}
# iort-overlap-smmu
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -216,7 +216,7 @@
let (_, Node::Its { id: to }) = self.output(smmu_raw, onward)? else {
return Err(IortRefused::Output { at: smmu_raw.at, reference: onward.reference });
};
- if its.replace(ItsDevice { its: to, device }).is_some() {
+ if its.replace(ItsDevice { its: to, device }).is_some() && false {
return Err(IortRefused::Overlap { id });
}
}
# iort-span-exclusive
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -160,7 +160,7 @@
impl Mapping {
fn maps(&self, id: u32) -> Option<u32> {
// `output + span` was checked not to wrap when the table was opened.
- (!self.single && id >= self.input && id - self.input <= self.span).then(|| self.output + (id - self.input))
+ (!self.single && id >= self.input && id - self.input < self.span).then(|| self.output + (id - self.input))
}
}
# iort-output-not-offset
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -160,7 +160,7 @@
impl Mapping {
fn maps(&self, id: u32) -> Option<u32> {
// `output + span` was checked not to wrap when the table was opened.
- (!self.single && id >= self.input && id - self.input <= self.span).then(|| self.output + (id - self.input))
+ (!self.single && id >= self.input && id - self.input <= self.span).then(|| self.output.wrapping_add(id))
}
}
# iort-any-segment
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -204,7 +204,7 @@
let mut route = None;
for raw in self.raw_nodes() {
let raw = raw?;
- if self.decode(raw)? != (Node::RootComplex { segment }) {
+ if !matches!(self.decode(raw)?, Node::RootComplex { .. }) {
continue;
}
for (mapping, id) in self.hits(raw, u32::from(rid)) {
# iort-gsiv-order
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -328,7 +328,7 @@
}
SMMUV3 => {
revised(4..=5)?;
- let gsiv = |i: usize| t.u32_at(at + SMMU_GSIVS + 4 * i).map(NonZeroU32::new).ok_or(short);
+ let gsiv = |i: usize| t.u32_at(at + SMMU_GSIVS + 4 * (3 - i)).map(NonZeroU32::new).ok_or(short);
Node::Smmuv3(Smmuv3 {
base: t.u64_at(at + SMMU_BASE).ok_or(short)?,
coherent: t.u32_at(at + SMMU_FLAGS).ok_or(short)? & SMMU_COHACC != 0,
# iort-cohacc-bit
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -52,7 +52,7 @@
const SMMU_GSIVS: usize = 44;
const SMMU_LEN: usize = 68;
/// Table 14, bit 0: `COHACC override`.
-const SMMU_COHACC: u32 = 1;
+const SMMU_COHACC: u32 = 2;
/// Why an IORT cannot be used. `at` is a node's offset in the table.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
# iort-segment-offset
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -43,7 +43,7 @@
/// Table 18: memory access properties (16..24), ATS attribute (24..28), PCI
/// segment number (28..32), then the address size limit and, from node
/// revision 4, the PASID capabilities and flags.
-const RC_SEGMENT: usize = 28;
+const RC_SEGMENT: usize = 24;
/// Table 13: base address (16..24), flags (24..28), a reserved word, VATOS
/// (32..40), model (40..44), the event, PRI, GERR and sync GSIVs (44..60),
/// proximity domain (60..64), DeviceID mapping index (64..68).
# iort-smmu-floor
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -50,7 +50,7 @@
const SMMU_BASE: usize = 16;
const SMMU_FLAGS: usize = 24;
const SMMU_GSIVS: usize = 44;
-const SMMU_LEN: usize = 68;
+const SMMU_LEN: usize = 64;
/// Table 14, bit 0: `COHACC override`.
const SMMU_COHACC: u32 = 1;
# iort-untranslated-id
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -209,7 +209,7 @@
}
for (mapping, id) in self.hits(raw, u32::from(rid)) {
let hop = match self.output(raw, mapping)? {
- (_, Node::Its { id: its }) => Route::Untranslated(ItsDevice { its, device: id }),
+ (_, Node::Its { id: its }) => Route::Untranslated(ItsDevice { its, device: u32::from(rid) }),
(smmu_raw, Node::Smmuv3(smmu)) => {
let mut its = None;
for (onward, device) in self.hits(smmu_raw, id) {
# madt-frame-select
--- a/toyos-acpi/src/madt.rs
+++ b/toyos-acpi/src/madt.rs
@@ -183,7 +183,7 @@
(entry_type == 0xD && declared >= 24).then(|| MsiFrame {
id: u32le(phys, base + 4),
base: u64le(phys, base + 8),
- spis: (u32le(phys, base + 16) & 1 != 0)
+ spis: (u32le(phys, base + 16) != 0)
.then(|| SpiRange { count: u16le(phys, base + 20), base: u16le(phys, base + 22) }),
})
}
# madt-frame-length
--- a/toyos-acpi/src/madt.rs
+++ b/toyos-acpi/src/madt.rs
@@ -180,7 +180,7 @@
/// Count (20..22), SPI Base (22..24).
fn msi_frame(self) -> Option<MsiFrame> {
let Self { phys, base, entry_type, declared } = self;
- (entry_type == 0xD && declared >= 24).then(|| MsiFrame {
+ (entry_type == 0xD).then(|| MsiFrame {
id: u32le(phys, base + 4),
base: u64le(phys, base + 8),
spis: (u32le(phys, base + 16) & 1 != 0)
# madt-frame-spi-fields
--- a/toyos-acpi/src/madt.rs
+++ b/toyos-acpi/src/madt.rs
@@ -184,7 +184,7 @@
id: u32le(phys, base + 4),
base: u64le(phys, base + 8),
spis: (u32le(phys, base + 16) & 1 != 0)
- .then(|| SpiRange { count: u16le(phys, base + 20), base: u16le(phys, base + 22) }),
+ .then(|| SpiRange { count: u16le(phys, base + 22), base: u16le(phys, base + 20) }),
})
}
# madt-halt-swallowed
--- a/toyos-acpi/src/madt.rs
+++ b/toyos-acpi/src/madt.rs
@@ -162,7 +162,7 @@
loop {
let structure = match entries.structure()? {
Ok(structure) => structure,
- Err(halt) => return Some(Err(halt)),
+ Err(_) => return None,
};
if let Some(frame) = structure.msi_frame() {
return Some(Ok(MsiController::Frame(frame))); |
|
Mutations of The patches# ste-abort-not-valid
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -24,7 +24,7 @@
/// `V` set and `Config` `0b000`: every transaction of the stream is
/// aborted, and no event is recorded for it. An entry of all zeroes
/// aborts too, and records `C_BAD_STE` each time.
- pub const ABORT: Self = Self([STE_V, 0, 0, 0, 0, 0, 0, 0]);
+ pub const ABORT: Self = Self([0, 0, 0, 0, 0, 0, 0, 0]);
/// The stream translated by stage 1 through the one context descriptor
/// at `context`: `S1ContextPtr` [55:6], `S1CDMax` [63:59] zero so a
# ste-bypass
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -12,7 +12,7 @@
/// `V`, bit [0].
const STE_V: u64 = 1 << 0;
/// `Config`, bits [3:1]: `0b101` is stage 1 translate, stage 2 bypass.
-const STE_STAGE1: u64 = 0b101 << 1;
+const STE_STAGE1: u64 = 0b100 << 1;
/// Doubleword 1: `S1CIR` [67:66] and `S1COR` [69:68] `0b01`, write-back
/// read-allocate, and `S1CSH` [71:70] `0b11`, inner shareable — how the unit
/// reads the context descriptor.
# ste-stage2
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -12,7 +12,7 @@
/// `V`, bit [0].
const STE_V: u64 = 1 << 0;
/// `Config`, bits [3:1]: `0b101` is stage 1 translate, stage 2 bypass.
-const STE_STAGE1: u64 = 0b101 << 1;
+const STE_STAGE1: u64 = 0b110 << 1;
/// Doubleword 1: `S1CIR` [67:66] and `S1COR` [69:68] `0b01`, write-back
/// read-allocate, and `S1CSH` [71:70] `0b11`, inner shareable — how the unit
/// reads the context descriptor.
# ste-stalld-bit
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -18,7 +18,7 @@
/// reads the context descriptor.
const STE_CD_CACHED: u64 = 0b01 << 2 | 0b01 << 4 | 0b11 << 6;
/// `S1STALLD`, bit [91].
-const STE_S1STALLD: u64 = 1 << 27;
+const STE_S1STALLD: u64 = 1 << 26;
impl Ste {
/// `V` set and `Config` `0b000`: every transaction of the stream is
# ste-stalld-always
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -32,7 +32,7 @@
/// the Non-secure EL1 regime, `EATS` [93:92] zero so ATS is refused, and
/// no stage 2 field.
pub const fn stage1(context: Phys<6>, unit: &Unit) -> Self {
- let stall = if unit.stall_disable() { STE_S1STALLD } else { 0 };
+ let stall = STE_S1STALLD;
Self([STE_V | STE_STAGE1 | context.get(), STE_CD_CACHED | stall, 0, 0, 0, 0, 0, 0])
}
}
# ste-stalld-never
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -32,7 +32,7 @@
/// the Non-secure EL1 regime, `EATS` [93:92] zero so ATS is refused, and
/// no stage 2 field.
pub const fn stage1(context: Phys<6>, unit: &Unit) -> Self {
- let stall = if unit.stall_disable() { STE_S1STALLD } else { 0 };
+ let stall = 0;
Self([STE_V | STE_STAGE1 | context.get(), STE_CD_CACHED | stall, 0, 0, 0, 0, 0, 0])
}
}
# ste-cd-attributes
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -16,7 +16,7 @@
/// Doubleword 1: `S1CIR` [67:66] and `S1COR` [69:68] `0b01`, write-back
/// read-allocate, and `S1CSH` [71:70] `0b11`, inner shareable — how the unit
/// reads the context descriptor.
-const STE_CD_CACHED: u64 = 0b01 << 2 | 0b01 << 4 | 0b11 << 6;
+const STE_CD_CACHED: u64 = 0b01 << 0 | 0b01 << 2 | 0b11 << 4;
/// `S1STALLD`, bit [91].
const STE_S1STALLD: u64 = 1 << 27;
# cd-ttb1-walked
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -70,7 +70,6 @@
pub const fn new(root: Phys<12>, asid: Asid, unit: &Unit) -> Self {
let word0 = CD_T0SZ
| CD_WALK
- | CD_EPD1
| CD_V
| unit.ips() << 32
| CD_AA64
# cd-not-valid
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -71,7 +71,6 @@
let word0 = CD_T0SZ
| CD_WALK
| CD_EPD1
- | CD_V
| unit.ips() << 32
| CD_AA64
| CD_FAULTS
# cd-shared-asid-set
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -75,7 +75,6 @@
| unit.ips() << 32
| CD_AA64
| CD_FAULTS
- | CD_ASET
| (asid.get() as u64) << 48;
Self([word0, root.get(), 0, crate::table::MAIR0 as u64, 0, 0, 0, 0])
}
# cd-raz-wi
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -57,7 +57,7 @@
/// `R` [45] records a translation-related fault and `A` [46] aborts its
/// transaction rather than completing it as read-as-zero, write-ignored;
/// `S` [44] stays clear, so none stalls (§5.5).
-const CD_FAULTS: u64 = 1 << 45 | 1 << 46;
+const CD_FAULTS: u64 = 1 << 45;
/// `ASET`, bit [47]: the ASID is the unit's own and no CPU process's.
const CD_ASET: u64 = 1 << 47;
# cd-unrecorded
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -57,7 +57,7 @@
/// `R` [45] records a translation-related fault and `A` [46] aborts its
/// transaction rather than completing it as read-as-zero, write-ignored;
/// `S` [44] stays clear, so none stalls (§5.5).
-const CD_FAULTS: u64 = 1 << 45 | 1 << 46;
+const CD_FAULTS: u64 = 1 << 46;
/// `ASET`, bit [47]: the ASID is the unit's own and no CPU process's.
const CD_ASET: u64 = 1 << 47;
# cd-stalls
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -57,7 +57,7 @@
/// `R` [45] records a translation-related fault and `A` [46] aborts its
/// transaction rather than completing it as read-as-zero, write-ignored;
/// `S` [44] stays clear, so none stalls (§5.5).
-const CD_FAULTS: u64 = 1 << 45 | 1 << 46;
+const CD_FAULTS: u64 = 1 << 44 | 1 << 45 | 1 << 46;
/// `ASET`, bit [47]: the ASID is the unit's own and no CPU process's.
const CD_ASET: u64 = 1 << 47;
# cd-asid-field
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -76,7 +76,7 @@
| CD_AA64
| CD_FAULTS
| CD_ASET
- | (asid.get() as u64) << 48;
+ | (asid.get() as u64) << 32;
Self([word0, root.get(), 0, crate::table::MAIR0 as u64, 0, 0, 0, 0])
}
}
# cd-t0sz
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -42,7 +42,7 @@
pub struct Cd(pub [u64; 8]);
/// `T0SZ`, bits [5:0]: a 48-bit input, walked from level 0.
-const CD_T0SZ: u64 = 64 - crate::table::INPUT_BITS as u64;
+const CD_T0SZ: u64 = crate::table::INPUT_BITS as u64;
/// `TG0` [7:6] zero is the 4 KiB granule; `IR0` [9:8] and `OR0` [11:10]
/// `0b01`, write-back write-allocate, and `SH0` [13:12] `0b11`, inner
/// shareable — how the unit walks the tables; `EPD0` [14] and `ENDI` [15]
# cd-aarch32
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -73,7 +73,6 @@
| CD_EPD1
| CD_V
| unit.ips() << 32
- | CD_AA64
| CD_FAULTS
| CD_ASET
| (asid.get() as u64) << 48;
# cd-ips-field
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -72,7 +72,7 @@
| CD_WALK
| CD_EPD1
| CD_V
- | unit.ips() << 32
+ | unit.ips() << 33
| CD_AA64
| CD_FAULTS
| CD_ASET
# cd-ttb0-word
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -77,6 +77,6 @@
| CD_FAULTS
| CD_ASET
| (asid.get() as u64) << 48;
- Self([word0, root.get(), 0, crate::table::MAIR0 as u64, 0, 0, 0, 0])
+ Self([word0, 0, root.get(), crate::table::MAIR0 as u64, 0, 0, 0, 0])
}
}
# cd-mair-word
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -77,6 +77,6 @@
| CD_FAULTS
| CD_ASET
| (asid.get() as u64) << 48;
- Self([word0, root.get(), 0, crate::table::MAIR0 as u64, 0, 0, 0, 0])
+ Self([word0, root.get(), crate::table::MAIR0 as u64, 0, 0, 0, 0, 0])
}
}
# unit-ips-52
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -211,7 +211,7 @@
40 => 0b010,
42 => 0b011,
44 => 0b100,
- _ => 0b101,
+ _ => 0b110,
}
}
# leaf-global
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -40,7 +40,7 @@
/// `PXN` [53] and `UXN` [54]: never executable.
const NEVER_EXECUTED: u64 = 1 << 53 | 1 << 54;
-const LEAF: u64 = VALID | AP_UNPRIVILEGED | AF | NOT_GLOBAL | NEVER_EXECUTED;
+const LEAF: u64 = VALID | AP_UNPRIVILEGED | AF | NEVER_EXECUTED;
/// What a device may do to memory mapped for it.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
# leaf-privileged-only
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -40,7 +40,7 @@
/// `PXN` [53] and `UXN` [54]: never executable.
const NEVER_EXECUTED: u64 = 1 << 53 | 1 << 54;
-const LEAF: u64 = VALID | AP_UNPRIVILEGED | AF | NOT_GLOBAL | NEVER_EXECUTED;
+const LEAF: u64 = VALID | AF | NOT_GLOBAL | NEVER_EXECUTED;
/// What a device may do to memory mapped for it.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
# leaf-no-access-flag
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -40,7 +40,7 @@
/// `PXN` [53] and `UXN` [54]: never executable.
const NEVER_EXECUTED: u64 = 1 << 53 | 1 << 54;
-const LEAF: u64 = VALID | AP_UNPRIVILEGED | AF | NOT_GLOBAL | NEVER_EXECUTED;
+const LEAF: u64 = VALID | AP_UNPRIVILEGED | NOT_GLOBAL | NEVER_EXECUTED;
/// What a device may do to memory mapped for it.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
# leaf-executable
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -40,7 +40,7 @@
/// `PXN` [53] and `UXN` [54]: never executable.
const NEVER_EXECUTED: u64 = 1 << 53 | 1 << 54;
-const LEAF: u64 = VALID | AP_UNPRIVILEGED | AF | NOT_GLOBAL | NEVER_EXECUTED;
+const LEAF: u64 = VALID | AP_UNPRIVILEGED | AF | NOT_GLOBAL;
/// What a device may do to memory mapped for it.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
# leaf-read-is-writable
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -89,7 +89,7 @@
let (tables, size, descriptor) = match leaf {
Leaf::Memory(block, access) => {
let access = match access {
- Access::Read => AP_READ_ONLY,
+ Access::Read => 0,
Access::ReadWrite => 0,
};
(3, 1u64 << 21, block.get() | LEAF | ATTR_MEMORY | INNER_SHAREABLE | access)
# leaf-write-is-read-only
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -90,7 +90,7 @@
Leaf::Memory(block, access) => {
let access = match access {
Access::Read => AP_READ_ONLY,
- Access::ReadWrite => 0,
+ Access::ReadWrite => AP_READ_ONLY,
};
(3, 1u64 << 21, block.get() | LEAF | ATTR_MEMORY | INNER_SHAREABLE | access)
}
# leaf-memory-as-device
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -92,7 +92,7 @@
Access::Read => AP_READ_ONLY,
Access::ReadWrite => 0,
};
- (3, 1u64 << 21, block.get() | LEAF | ATTR_MEMORY | INNER_SHAREABLE | access)
+ (3, 1u64 << 21, block.get() | LEAF | ATTR_DEVICE | INNER_SHAREABLE | access)
}
Leaf::Doorbell(page) => (4, 1u64 << 12, page.get() | LEAF | TABLE_OR_PAGE | ATTR_DEVICE),
};
# doorbell-as-block
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -94,7 +94,7 @@
};
(3, 1u64 << 21, block.get() | LEAF | ATTR_MEMORY | INNER_SHAREABLE | access)
}
- Leaf::Doorbell(page) => (4, 1u64 << 12, page.get() | LEAF | TABLE_OR_PAGE | ATTR_DEVICE),
+ Leaf::Doorbell(page) => (4, 1u64 << 12, page.get() | LEAF | ATTR_DEVICE),
};
if at >> INPUT_BITS != 0 || at & (size - 1) != 0 {
return None;
# doorbell-as-memory
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -94,7 +94,7 @@
};
(3, 1u64 << 21, block.get() | LEAF | ATTR_MEMORY | INNER_SHAREABLE | access)
}
- Leaf::Doorbell(page) => (4, 1u64 << 12, page.get() | LEAF | TABLE_OR_PAGE | ATTR_DEVICE),
+ Leaf::Doorbell(page) => (4, 1u64 << 12, page.get() | LEAF | TABLE_OR_PAGE | ATTR_MEMORY),
};
if at >> INPUT_BITS != 0 || at & (size - 1) != 0 {
return None;
# doorbell-at-level-2
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -94,7 +94,7 @@
};
(3, 1u64 << 21, block.get() | LEAF | ATTR_MEMORY | INNER_SHAREABLE | access)
}
- Leaf::Doorbell(page) => (4, 1u64 << 12, page.get() | LEAF | TABLE_OR_PAGE | ATTR_DEVICE),
+ Leaf::Doorbell(page) => (3, 1u64 << 12, page.get() | LEAF | TABLE_OR_PAGE | ATTR_DEVICE),
};
if at >> INPUT_BITS != 0 || at & (size - 1) != 0 {
return None;
# plan-unaligned
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -96,7 +96,7 @@
}
Leaf::Doorbell(page) => (4, 1u64 << 12, page.get() | LEAF | TABLE_OR_PAGE | ATTR_DEVICE),
};
- if at >> INPUT_BITS != 0 || at & (size - 1) != 0 {
+ if at >> INPUT_BITS != 0 {
return None;
}
const fn index(at: u64, level: u32) -> usize {
# plan-past-input
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -96,7 +96,7 @@
}
Leaf::Doorbell(page) => (4, 1u64 << 12, page.get() | LEAF | TABLE_OR_PAGE | ATTR_DEVICE),
};
- if at >> INPUT_BITS != 0 || at & (size - 1) != 0 {
+ if at & (size - 1) != 0 {
return None;
}
const fn index(at: u64, level: u32) -> usize {
# plan-index-shift
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -100,7 +100,7 @@
return None;
}
const fn index(at: u64, level: u32) -> usize {
- (at >> (39 - 9 * level) & 0x1FF) as usize
+ (at >> (38 - 9 * level) & 0x1FF) as usize
}
Some(Path { indices: [index(at, 0), index(at, 1), index(at, 2), index(at, 3)], tables, descriptor })
}
# plan-index-width
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -100,7 +100,7 @@
return None;
}
const fn index(at: u64, level: u32) -> usize {
- (at >> (39 - 9 * level) & 0x1FF) as usize
+ (at >> (39 - 9 * level) & 0xFF) as usize
}
Some(Path { indices: [index(at, 0), index(at, 1), index(at, 2), index(at, 3)], tables, descriptor })
}
# entry-page-as-table
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -121,7 +121,7 @@
pub const fn entry(descriptor: u64, level: usize) -> Entry {
if descriptor & VALID == 0 {
Entry::Invalid
- } else if level < LEVELS - 1 && descriptor & TABLE_OR_PAGE != 0 {
+ } else if descriptor & TABLE_OR_PAGE != 0 {
Entry::Table(Phys(descriptor & 0x0000_FFFF_FFFF_F000))
} else {
Entry::Mapped
# entry-invalid-as-table
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -119,7 +119,7 @@
/// `descriptor` as the walk reads it at `level`: bit [1] names a table above
/// level 3 and a page at it, and a table's address is bits [47:12].
pub const fn entry(descriptor: u64, level: usize) -> Entry {
- if descriptor & VALID == 0 {
+ if descriptor == 0 {
Entry::Invalid
} else if level < LEVELS - 1 && descriptor & TABLE_OR_PAGE != 0 {
Entry::Table(Phys(descriptor & 0x0000_FFFF_FFFF_F000))
# next-not-table
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -61,7 +61,7 @@
/// The descriptor naming the next table down, at levels 0 to 2. Its
/// hierarchical fields stay clear: the leaf alone decides the access.
pub const fn next(table: Phys<12>) -> u64 {
- table.get() | TABLE_OR_PAGE | VALID
+ table.get() | VALID
}
/// One mapping, planned: the index to follow in each table from the root,
# mair-order
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -15,7 +15,7 @@
/// `CD.MAIR0`: attribute 0 is Device-nGnRE (`0x04`), which the message page
/// is mapped with, and attribute 1 Normal write-back memory (`0xFF`).
-pub const MAIR0: u32 = 0x04 | 0xFF << 8;
+pub const MAIR0: u32 = 0xFF | 0x04 << 8;
const ATTR_DEVICE: u64 = 0 << 2;
const ATTR_MEMORY: u64 = 1 << 2;
# queue-full-is-empty
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -40,7 +40,7 @@
/// Nothing can be produced: the indexes are equal and the wrap flags differ.
pub const fn is_full(self, prod: u32, cons: u32) -> bool {
- self.position(prod) ^ self.position(cons) == 1 << self.log2size
+ self.position(prod) == self.position(cons)
}
/// The position after `index`, wrap flag toggled where it passes the
# queue-no-wrap-flag
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -46,7 +46,7 @@
/// The position after `index`, wrap flag toggled where it passes the
/// top: what the owner of an index writes back, index and flag at once.
pub const fn after(self, index: u32) -> u32 {
- self.position(self.position(index) + 1)
+ (self.position(index) + 1) & ((1 << self.log2size) - 1)
}
}
# queue-after-overflows
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -46,7 +46,7 @@
/// The position after `index`, wrap flag toggled where it passes the
/// top: what the owner of an index writes back, index and flag at once.
pub const fn after(self, index: u32) -> u32 {
- self.position(self.position(index) + 1)
+ self.position(index + 1)
}
}
# queue-empty-ignores-wrap
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -35,7 +35,7 @@
/// Nothing to consume: the indexes and their wrap flags are equal.
pub const fn is_empty(self, prod: u32, cons: u32) -> bool {
- self.position(prod) == self.position(cons)
+ self.slot(prod) == self.slot(cons)
}
/// Nothing can be produced: the indexes are equal and the wrap flags differ.
# queue-size-bound
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -15,7 +15,7 @@
/// `None` past the 19 bits an index register's `WR` and `RD` fields with
/// their wrap flag can hold (`IDR1.CMDQS`, `EVENTQS`).
pub const fn new(log2size: u8) -> Option<Self> {
- if log2size <= 19 {
+ if log2size <= 31 {
Some(Self { log2size })
} else {
None
# cmd-sync-signal-field
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -102,7 +102,7 @@
Signal::Irq => 0b01,
Signal::Sev => 0b10,
};
- [0x46 | cs << 12, 0]
+ [0x46 | cs << 11, 0]
}
}
}
# cmd-sync-irq-is-sev
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -99,7 +99,7 @@
Self::Sync(signal) => {
let cs = match signal {
Signal::None => 0b00,
- Signal::Irq => 0b01,
+ Signal::Irq => 0b10,
Signal::Sev => 0b10,
};
[0x46 | cs << 12, 0]
# cmd-forget-stream-nonleaf
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -87,7 +87,7 @@
pub const fn words(self) -> [u64; 2] {
match self {
// StreamID [63:32]; Leaf [64].
- Self::ForgetStream(stream) => [0x03 | (stream as u64) << 32, 1],
+ Self::ForgetStream(stream) => [0x03 | (stream as u64) << 32, 0],
// StreamID [63:32], SubstreamID [31:12] zero; Leaf [64].
Self::ForgetContext(stream) => [0x05 | (stream as u64) << 32, 1],
// `CMD_CFGI_STE_RANGE` with Range [68:64] of 31.
# cmd-forget-stream-field
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -87,7 +87,7 @@
pub const fn words(self) -> [u64; 2] {
match self {
// StreamID [63:32]; Leaf [64].
- Self::ForgetStream(stream) => [0x03 | (stream as u64) << 32, 1],
+ Self::ForgetStream(stream) => [0x03 | (stream as u64) << 12, 1],
// StreamID [63:32], SubstreamID [31:12] zero; Leaf [64].
Self::ForgetContext(stream) => [0x05 | (stream as u64) << 32, 1],
// `CMD_CFGI_STE_RANGE` with Range [68:64] of 31.
# cmd-forget-all-range
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -91,7 +91,7 @@
// StreamID [63:32], SubstreamID [31:12] zero; Leaf [64].
Self::ForgetContext(stream) => [0x05 | (stream as u64) << 32, 1],
// `CMD_CFGI_STE_RANGE` with Range [68:64] of 31.
- Self::ForgetAll => [0x04, 31],
+ Self::ForgetAll => [0x04, 0],
// ASID [63:48], VMID [47:32].
Self::InvalidateAsid(asid) => [0x11 | (asid.get() as u64) << 48, 0],
Self::InvalidateAll => [0x30, 0],
# cmd-asid-field
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -93,7 +93,7 @@
// `CMD_CFGI_STE_RANGE` with Range [68:64] of 31.
Self::ForgetAll => [0x04, 31],
// ASID [63:48], VMID [47:32].
- Self::InvalidateAsid(asid) => [0x11 | (asid.get() as u64) << 48, 0],
+ Self::InvalidateAsid(asid) => [0x11 | (asid.get() as u64) << 32, 0],
Self::InvalidateAll => [0x30, 0],
// CS [13:12].
Self::Sync(signal) => {
# cmd-invalidate-all-opcode
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -94,7 +94,7 @@
Self::ForgetAll => [0x04, 31],
// ASID [63:48], VMID [47:32].
Self::InvalidateAsid(asid) => [0x11 | (asid.get() as u64) << 48, 0],
- Self::InvalidateAll => [0x30, 0],
+ Self::InvalidateAll => [0x10, 0],
// CS [13:12].
Self::Sync(signal) => {
let cs = match signal {
# event-rnw-bit
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -197,7 +197,7 @@
};
let attempt = match code {
Code::Translation | Code::AddressSize | Code::AccessFlag | Code::Permission => {
- Some(Attempt { address: record[2], write: record[1] & 1 << 35 == 0 })
+ Some(Attempt { address: record[2], write: record[1] & 1 << 34 == 0 })
}
_ => None,
};
# event-rnw-polarity
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -197,7 +197,7 @@
};
let attempt = match code {
Code::Translation | Code::AddressSize | Code::AccessFlag | Code::Permission => {
- Some(Attempt { address: record[2], write: record[1] & 1 << 35 == 0 })
+ Some(Attempt { address: record[2], write: record[1] & 1 << 35 != 0 })
}
_ => None,
};
# event-address-word
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -197,7 +197,7 @@
};
let attempt = match code {
Code::Translation | Code::AddressSize | Code::AccessFlag | Code::Permission => {
- Some(Attempt { address: record[2], write: record[1] & 1 << 35 == 0 })
+ Some(Attempt { address: record[3], write: record[1] & 1 << 35 == 0 })
}
_ => None,
};
# event-stream-field
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -201,5 +201,5 @@
}
_ => None,
};
- Event { stream: (record[0] >> 32) as u32, code, attempt }
+ Event { stream: (record[0] >> 12) as u32, code, attempt }
}
# event-permission-unnamed
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -188,7 +188,6 @@
0x10 => Code::Translation,
0x11 => Code::AddressSize,
0x12 => Code::AccessFlag,
- 0x13 => Code::Permission,
0x20 => Code::TlbConflict,
0x21 => Code::ConfigurationConflict,
0x24 => Code::PageRequest,
# event-attempt-on-any
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -199,7 +199,7 @@
Code::Translation | Code::AddressSize | Code::AccessFlag | Code::Permission => {
Some(Attempt { address: record[2], write: record[1] & 1 << 35 == 0 })
}
- _ => None,
+ _ => Some(Attempt { address: record[2], write: true }),
};
Event { stream: (record[0] >> 32) as u32, code, attempt }
}
# probe-no-stage1
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -140,7 +140,7 @@
/// §6.3.1, §6.3.2 and §6.3.6: the three identification registers, judged.
pub const fn probe(idr0: u32, idr1: u32, idr5: u32) -> Result<Unit, Lacks> {
- if idr0 & 1 << 1 == 0 {
+ if false {
return Err(Lacks::Stage1);
}
if idr0 & 1 << 3 == 0 {
# probe-ttf-bit
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -143,7 +143,7 @@
if idr0 & 1 << 1 == 0 {
return Err(Lacks::Stage1);
}
- if idr0 & 1 << 3 == 0 {
+ if idr0 & 1 << 2 == 0 {
return Err(Lacks::Aarch64Tables);
}
// `TTENDIAN` [22:21]: `0b00` mixed and `0b10` little-endian can be set to little-endian.
# probe-big-endian
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -147,7 +147,7 @@
return Err(Lacks::Aarch64Tables);
}
// `TTENDIAN` [22:21]: `0b00` mixed and `0b10` little-endian can be set to little-endian.
- if idr0 >> 21 & 0b11 == 0b11 {
+ if false {
return Err(Lacks::LittleEndianTables);
}
// `STALL_MODEL` [25:24]: `0b00` stall and terminate, `0b01` terminate only.
# probe-forced-stall
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -153,7 +153,7 @@
// `STALL_MODEL` [25:24]: `0b00` stall and terminate, `0b01` terminate only.
let stall = match idr0 >> 24 & 0b11 {
0b00 => true,
- 0b01 => false,
+ 0b01 | 0b10 => false,
other => return Err(Lacks::Termination(other as u8)),
};
if idr5 & 1 << 4 == 0 {
# probe-no-4k
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -156,7 +156,7 @@
0b01 => false,
other => return Err(Lacks::Termination(other as u8)),
};
- if idr5 & 1 << 4 == 0 {
+ if false {
return Err(Lacks::Granule4K);
}
if idr1 & (1 << 30 | 1 << 29) != 0 {
# probe-preset
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -159,7 +159,7 @@
if idr5 & 1 << 4 == 0 {
return Err(Lacks::Granule4K);
}
- if idr1 & (1 << 30 | 1 << 29) != 0 {
+ if idr1 & (1 << 30) != 0 {
return Err(Lacks::FixedStructures);
}
let stream_bits = (idr1 & 0x3F) as u8;
# probe-stream-bits-bound
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -165,7 +165,7 @@
let stream_bits = (idr1 & 0x3F) as u8;
let command_queue_log2 = (idr1 >> 21 & 0x1F) as u8;
let event_queue_log2 = (idr1 >> 16 & 0x1F) as u8;
- if stream_bits > 32 {
+ if stream_bits > 63 {
return Err(Lacks::Size(stream_bits));
}
if command_queue_log2 > 19 {
# probe-queue-bound
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -168,7 +168,7 @@
if stream_bits > 32 {
return Err(Lacks::Size(stream_bits));
}
- if command_queue_log2 > 19 {
+ if command_queue_log2 > 31 {
return Err(Lacks::Size(command_queue_log2));
}
if event_queue_log2 > 19 {
# probe-eventq-field
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -164,7 +164,7 @@
}
let stream_bits = (idr1 & 0x3F) as u8;
let command_queue_log2 = (idr1 >> 21 & 0x1F) as u8;
- let event_queue_log2 = (idr1 >> 16 & 0x1F) as u8;
+ let event_queue_log2 = (idr1 >> 21 & 0x1F) as u8;
if stream_bits > 32 {
return Err(Lacks::Size(stream_bits));
}
# probe-cohacc-bit
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -179,7 +179,7 @@
command_queue_log2,
event_queue_log2,
output_bits: [32, 36, 40, 42, 44, 48, 52, 56][(idr5 & 0b111) as usize],
- coherent: idr0 & 1 << 4 != 0,
+ coherent: idr0 & 1 << 5 != 0,
asid16: idr0 & 1 << 12 != 0,
stall,
})
# asid-wider-than-unit
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -189,7 +189,7 @@
/// `tag` as an ASID of this unit: eight bits where `IDR0.ASID16` is
/// clear, under which a wider one makes its context descriptor ILLEGAL.
pub const fn asid(&self, tag: u16) -> Option<Asid> {
- if self.asid16 || tag <= 0xFF {
+ if true {
Some(Asid(tag))
} else {
None
# strtab-misaligned
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -221,7 +221,7 @@
/// where the unit takes fewer StreamID bits, or the table is not aligned
/// to its own size as the unit reads its address.
pub const fn stream_table(&self, table: Phys<6>, log2size: u8) -> Option<(u64, u32)> {
- if log2size > self.stream_bits || table.get() & ((64 << log2size) - 1) != 0 {
+ if log2size > self.stream_bits {
return None;
}
Some((1 << 62 | table.get(), log2size as u32))
# strtab-past-streams
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -221,7 +221,7 @@
/// where the unit takes fewer StreamID bits, or the table is not aligned
/// to its own size as the unit reads its address.
pub const fn stream_table(&self, table: Phys<6>, log2size: u8) -> Option<(u64, u32)> {
- if log2size > self.stream_bits || table.get() & ((64 << log2size) - 1) != 0 {
+ if table.get() & ((64 << log2size) - 1) != 0 {
return None;
}
Some((1 << 62 | table.get(), log2size as u32))
# strtab-no-read-allocate
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -224,7 +224,7 @@
if log2size > self.stream_bits || table.get() & ((64 << log2size) - 1) != 0 {
return None;
}
- Some((1 << 62 | table.get(), log2size as u32))
+ Some((table.get(), log2size as u32))
}
/// `SMMU_CMDQ_BASE` (§6.3.26) for a queue of `1 << log2size` 16-byte
# cmdq-past-unit
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -232,7 +232,7 @@
/// past the unit's `CMDQS`, or where the queue is not aligned to the
/// larger of its size and 32 bytes.
pub const fn command_queue(&self, queue: Phys<5>, log2size: u8) -> Option<u64> {
- if log2size > self.command_queue_log2 || queue.get() & ((16 << log2size) - 1) != 0 {
+ if queue.get() & ((16 << log2size) - 1) != 0 {
return None;
}
Some(1 << 62 | queue.get() | log2size as u64)
# cmdq-misaligned
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -232,7 +232,7 @@
/// past the unit's `CMDQS`, or where the queue is not aligned to the
/// larger of its size and 32 bytes.
pub const fn command_queue(&self, queue: Phys<5>, log2size: u8) -> Option<u64> {
- if log2size > self.command_queue_log2 || queue.get() & ((16 << log2size) - 1) != 0 {
+ if log2size > self.command_queue_log2 {
return None;
}
Some(1 << 62 | queue.get() | log2size as u64)
# eventq-entry-size
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -241,7 +241,7 @@
/// `SMMU_EVENTQ_BASE` (§6.3.29) for a queue of `1 << log2size` 32-byte
/// records: `WA` [62], the address, `LOG2SIZE` [4:0].
pub const fn event_queue(&self, queue: Phys<5>, log2size: u8) -> Option<u64> {
- if log2size > self.event_queue_log2 || queue.get() & ((32 << log2size) - 1) != 0 {
+ if log2size > self.event_queue_log2 || queue.get() & ((16 << log2size) - 1) != 0 {
return None;
}
Some(1 << 62 | queue.get() | log2size as u64)
# eventq-past-unit
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -241,7 +241,7 @@
/// `SMMU_EVENTQ_BASE` (§6.3.29) for a queue of `1 << log2size` 32-byte
/// records: `WA` [62], the address, `LOG2SIZE` [4:0].
pub const fn event_queue(&self, queue: Phys<5>, log2size: u8) -> Option<u64> {
- if log2size > self.event_queue_log2 || queue.get() & ((32 << log2size) - 1) != 0 {
+ if queue.get() & ((32 << log2size) - 1) != 0 {
return None;
}
Some(1 << 62 | queue.get() | log2size as u64)
# errors-not-toggled
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -59,7 +59,7 @@
/// `SMMU_GERROR` (§6.3.19): an error is active while its bit differs from
/// `SMMU_GERRORN`'s, and writing `GERRORN` equal acknowledges it (§7.5).
pub const fn active_errors(gerror: u32, gerrorn: u32) -> u32 {
- gerror ^ gerrorn
+ gerror & !gerrorn
}
/// `SMMU_GERROR.CMDQ_ERR`: the command queue stopped on [`CommandError`].
# cmd-error-field
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -85,7 +85,7 @@
}
pub const fn command_error(cons: u32) -> CommandError {
- match (cons >> 24 & 0x7F) as u8 {
+ match (cons >> 24) as u8 {
0 => CommandError::None,
1 => CommandError::Illegal,
2 => CommandError::Abort,
# cr1-table-shareability
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -38,7 +38,7 @@
/// inner-shareable write-back memory — `TABLE_SH` [11:10], `TABLE_OC` [9:8],
/// `TABLE_IC` [7:6], `QUEUE_SH` [5:4], `QUEUE_OC` [3:2], `QUEUE_IC` [1:0],
/// each shareability `0b11` and each cacheability `0b01`.
-pub const CR1_WRITE_BACK: u32 = 0b11 << 10 | 0b01 << 8 | 0b01 << 6 | 0b11 << 4 | 0b01 << 2 | 0b01;
+pub const CR1_WRITE_BACK: u32 = 0b11 << 12 | 0b01 << 8 | 0b01 << 6 | 0b11 << 4 | 0b01 << 2 | 0b01;
/// `SMMU_CR2` (§6.3.12): `RECINVSID` [1], so a transaction under a StreamID
/// past the stream table is recorded as well as aborted, and `PTM` [2], so
# cr2-broadcast
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -44,7 +44,7 @@
/// past the stream table is recorded as well as aborted, and `PTM` [2], so
/// no CPU's broadcast TLB invalidation reaches the unit's entries: its ASIDs
/// are its own. `E2H` [0] stays clear.
-pub const CR2_RECORD_PRIVATE: u32 = 1 << 1 | 1 << 2;
+pub const CR2_RECORD_PRIVATE: u32 = 1 << 1;
/// `SMMU_GBPA` (§6.3.15): what happens to every transaction while `SMMUEN`
/// is clear. `ABORT` [20] aborts them; a write takes effect by carrying
# gbpa-abort-bit
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -49,7 +49,7 @@
/// `SMMU_GBPA` (§6.3.15): what happens to every transaction while `SMMUEN`
/// is clear. `ABORT` [20] aborts them; a write takes effect by carrying
/// `Update` [31], which reads back set until the unit has taken it (§6.3.15.1).
-pub const GBPA_ABORT: u32 = 1 << 20;
+pub const GBPA_ABORT: u32 = 1 << 19;
pub const GBPA_UPDATE: u32 = 1 << 31;
/// `SMMU_IRQ_CTRL` (§6.3.17), and `SMMU_IRQ_CTRLACK` as `SMMU_CR0ACK`.
# phys-past-48
--- a/toyos-smmu/src/lib.rs
+++ b/toyos-smmu/src/lib.rs
@@ -32,7 +32,7 @@
impl<const ALIGN: u32> Phys<ALIGN> {
pub const fn new(address: u64) -> Option<Self> {
- if address >> 48 == 0 && address & ((1 << ALIGN) - 1) == 0 {
+ if address & ((1 << ALIGN) - 1) == 0 {
Some(Self(address))
} else {
None
# phys-unaligned
--- a/toyos-smmu/src/lib.rs
+++ b/toyos-smmu/src/lib.rs
@@ -32,7 +32,7 @@
impl<const ALIGN: u32> Phys<ALIGN> {
pub const fn new(address: u64) -> Option<Self> {
- if address >> 48 == 0 && address & ((1 << ALIGN) - 1) == 0 {
+ if address >> 48 == 0 {
Some(Self(address))
} else {
None |
|
Mutations of The patches# its-mapd-size
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -39,7 +39,7 @@
match self {
// Size [4:0] of doubleword 1 is the EventID bits minus one; ITT_addr [51:8] of doubleword 2.
Self::MapDevice { device: id, table, events } => {
- [device(0x08, id), (events.0 - 1) as u64, V | table.get(), 0]
+ [device(0x08, id), events.0 as u64, V | table.get(), 0]
}
Self::UnmapDevice { device: id } => [device(0x08, id), 0, 0, 0],
// RDbase [51:16] and ICID [15:0] of doubleword 2.
# its-mapd-not-valid
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -39,7 +39,7 @@
match self {
// Size [4:0] of doubleword 1 is the EventID bits minus one; ITT_addr [51:8] of doubleword 2.
Self::MapDevice { device: id, table, events } => {
- [device(0x08, id), (events.0 - 1) as u64, V | table.get(), 0]
+ [device(0x08, id), (events.0 - 1) as u64, table.get(), 0]
}
Self::UnmapDevice { device: id } => [device(0x08, id), 0, 0, 0],
// RDbase [51:16] and ICID [15:0] of doubleword 2.
# its-unmapd-valid
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -41,7 +41,7 @@
Self::MapDevice { device: id, table, events } => {
[device(0x08, id), (events.0 - 1) as u64, V | table.get(), 0]
}
- Self::UnmapDevice { device: id } => [device(0x08, id), 0, 0, 0],
+ Self::UnmapDevice { device: id } => [device(0x08, id), 0, V, 0],
// RDbase [51:16] and ICID [15:0] of doubleword 2.
Self::MapCollection { collection, target } => [0x09, 0, V | target.0 << 16 | collection as u64, 0],
// pINTID [63:32] of doubleword 1; ICID [15:0] of doubleword 2.
# its-mapc-rdbase-field
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -43,7 +43,7 @@
}
Self::UnmapDevice { device: id } => [device(0x08, id), 0, 0, 0],
// RDbase [51:16] and ICID [15:0] of doubleword 2.
- Self::MapCollection { collection, target } => [0x09, 0, V | target.0 << 16 | collection as u64, 0],
+ Self::MapCollection { collection, target } => [0x09, 0, V | target.0 << 32 | collection as u64, 0],
// pINTID [63:32] of doubleword 1; ICID [15:0] of doubleword 2.
Self::MapEvent { device: id, event, lpi, collection } => {
[device(0x0A, id), (lpi.intid() as u64) << 32 | event as u64, collection as u64, 0]
# its-mapc-not-valid
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -43,7 +43,7 @@
}
Self::UnmapDevice { device: id } => [device(0x08, id), 0, 0, 0],
// RDbase [51:16] and ICID [15:0] of doubleword 2.
- Self::MapCollection { collection, target } => [0x09, 0, V | target.0 << 16 | collection as u64, 0],
+ Self::MapCollection { collection, target } => [0x09, 0, target.0 << 16 | collection as u64, 0],
// pINTID [63:32] of doubleword 1; ICID [15:0] of doubleword 2.
Self::MapEvent { device: id, event, lpi, collection } => {
[device(0x0A, id), (lpi.intid() as u64) << 32 | event as u64, collection as u64, 0]
# its-mapti-fields-swapped
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -46,7 +46,7 @@
Self::MapCollection { collection, target } => [0x09, 0, V | target.0 << 16 | collection as u64, 0],
// pINTID [63:32] of doubleword 1; ICID [15:0] of doubleword 2.
Self::MapEvent { device: id, event, lpi, collection } => {
- [device(0x0A, id), (lpi.intid() as u64) << 32 | event as u64, collection as u64, 0]
+ [device(0x0A, id), (event as u64) << 32 | lpi.intid() as u64, collection as u64, 0]
}
Self::Reconfigure { device: id, event } => [device(0x0C, id), event as u64, 0, 0],
Self::Discard { device: id, event } => [device(0x0F, id), event as u64, 0, 0],
# its-mapti-collection-word
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -46,7 +46,7 @@
Self::MapCollection { collection, target } => [0x09, 0, V | target.0 << 16 | collection as u64, 0],
// pINTID [63:32] of doubleword 1; ICID [15:0] of doubleword 2.
Self::MapEvent { device: id, event, lpi, collection } => {
- [device(0x0A, id), (lpi.intid() as u64) << 32 | event as u64, collection as u64, 0]
+ [device(0x0A, id), (lpi.intid() as u64) << 32 | event as u64, 0, collection as u64]
}
Self::Reconfigure { device: id, event } => [device(0x0C, id), event as u64, 0, 0],
Self::Discard { device: id, event } => [device(0x0F, id), event as u64, 0, 0],
# its-device-field
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -34,7 +34,7 @@
pub const fn words(self) -> [u64; 4] {
// DeviceID is bits [63:32] of doubleword 0, and EventID bits [31:0] of doubleword 1.
const fn device(number: u64, device: u32) -> u64 {
- number | (device as u64) << 32
+ number | (device as u64) << 8
}
match self {
// Size [4:0] of doubleword 1 is the EventID bits minus one; ITT_addr [51:8] of doubleword 2.
# its-sync-rdbase-field
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -50,7 +50,7 @@
}
Self::Reconfigure { device: id, event } => [device(0x0C, id), event as u64, 0, 0],
Self::Discard { device: id, event } => [device(0x0F, id), event as u64, 0, 0],
- Self::Sync(target) => [0x05, 0, target.0 << 16, 0],
+ Self::Sync(target) => [0x05, 0, target.0, 0],
}
}
}
# its-inv-is-discard
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -48,7 +48,7 @@
Self::MapEvent { device: id, event, lpi, collection } => {
[device(0x0A, id), (lpi.intid() as u64) << 32 | event as u64, collection as u64, 0]
}
- Self::Reconfigure { device: id, event } => [device(0x0C, id), event as u64, 0, 0],
+ Self::Reconfigure { device: id, event } => [device(0x0F, id), event as u64, 0, 0],
Self::Discard { device: id, event } => [device(0x0F, id), event as u64, 0, 0],
Self::Sync(target) => [0x05, 0, target.0 << 16, 0],
}
# its-target-form-swapped
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -136,7 +136,7 @@
/// The redistributor at `frame` whose `GICR_TYPER.Processor_Number` is
/// `number`, as this ITS names it.
pub const fn target(&self, number: u16, frame: Phys<16>) -> Target {
- Target(if self.physical_targets { frame.get() >> 16 } else { number as u64 })
+ Target(if !self.physical_targets { frame.get() >> 16 } else { number as u64 })
}
}
# its-events-unbounded
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -120,7 +120,7 @@
/// A translation table of `1 << bits` events. `None` for no bit, or more
/// than the ITS's EventIDs have.
pub const fn events(&self, bits: u8) -> Option<EventBits> {
- if bits >= 1 && bits <= self.event_bits {
+ if bits >= 1 {
Some(EventBits(bits))
} else {
None
# its-events-zero
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -120,7 +120,7 @@
/// A translation table of `1 << bits` events. `None` for no bit, or more
/// than the ITS's EventIDs have.
pub const fn events(&self, bits: u8) -> Option<EventBits> {
- if bits >= 1 && bits <= self.event_bits {
+ if bits <= self.event_bits {
Some(EventBits(bits))
} else {
None
# its-itt-bytes
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -130,7 +130,7 @@
/// The zeroed bytes `MAPD` is given for that table, at a 256-byte
/// aligned address.
pub const fn itt_bytes(&self, events: EventBits) -> u64 {
- (self.itt_entry_bytes as u64) << events.0
+ (self.itt_entry_bytes as u64) << (events.0 - 1)
}
/// The redistributor at `frame` whose `GICR_TYPER.Processor_Number` is
# its-no-physical-lpis
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -94,7 +94,7 @@
}
pub const fn probe(typer: u64) -> Result<Its, Lacks> {
- if typer & 1 == 0 {
+ if false {
return Err(Lacks::PhysicalLpis);
}
Ok(Its {
# its-typer-minus-one
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -98,7 +98,7 @@
return Err(Lacks::PhysicalLpis);
}
Ok(Its {
- event_bits: (typer >> 8 & 0x1F) as u8 + 1,
+ event_bits: (typer >> 8 & 0x1F) as u8,
device_bits: (typer >> 13 & 0x1F) as u8 + 1,
itt_entry_bytes: (typer >> 4 & 0xF) as u8 + 1,
collections_held: (typer >> 24) as u8,
# its-typer-devbits-field
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -99,7 +99,7 @@
}
Ok(Its {
event_bits: (typer >> 8 & 0x1F) as u8 + 1,
- device_bits: (typer >> 13 & 0x1F) as u8 + 1,
+ device_bits: (typer >> 12 & 0x1F) as u8 + 1,
itt_entry_bytes: (typer >> 4 & 0xF) as u8 + 1,
collections_held: (typer >> 24) as u8,
physical_targets: typer & 1 << 19 != 0,
# its-typer-pta-bit
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -102,7 +102,7 @@
device_bits: (typer >> 13 & 0x1F) as u8 + 1,
itt_entry_bytes: (typer >> 4 & 0xF) as u8 + 1,
collections_held: (typer >> 24) as u8,
- physical_targets: typer & 1 << 19 != 0,
+ physical_targets: typer & 1 << 18 != 0,
})
}
# its-table-type-field
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -175,7 +175,7 @@
/// entry (`Entry_Size` [52:48] plus one) and the page size it holds — which
/// an ITS may fix, so it is read back after [`baser`] is written.
pub const fn table(baser: u64) -> (Table, u8, PageSize) {
- let kind = match baser >> 56 & 0b111 {
+ let kind = match baser >> 59 & 0b111 {
0b000 => Table::Unimplemented,
0b001 => Table::Devices,
0b100 => Table::Collections,
# its-table-collections
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -178,7 +178,7 @@
let kind = match baser >> 56 & 0b111 {
0b000 => Table::Unimplemented,
0b001 => Table::Devices,
- 0b100 => Table::Collections,
+ 0b010 => Table::Collections,
other => Table::Other(other as u8),
};
let page = match baser >> 8 & 0b11 {
# its-table-entry-size
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -187,7 +187,7 @@
// `0b11` is reserved and treated as `0b10`.
_ => PageSize::K64,
};
- (kind, (baser >> 48 & 0x1F) as u8 + 1, page)
+ (kind, (baser >> 48 & 0x1F) as u8, page)
}
/// `InnerCache` `0b111`, read-allocate write-allocate write-back, with
# its-baser-pages-bound
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -201,7 +201,7 @@
/// `Page_Size` [9:8], `Size` [7:0] the pages minus one. `None` for no page or
/// more than the 256 the field counts.
pub const fn baser(at: Phys<16>, page: PageSize, pages: u16) -> Option<u64> {
- if pages == 0 || pages > 256 {
+ if pages == 0 {
return None;
}
let size = match page {
# its-baser-size-not-minus-one
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -209,7 +209,7 @@
PageSize::K16 => 0b01,
PageSize::K64 => 0b10,
};
- Some(VALID | CACHED | at.get() | size << 8 | (pages - 1) as u64)
+ Some(VALID | CACHED | at.get() | size << 8 | (pages as u64 & 0xFF))
}
/// The ITS's command queue: `pages` 4 KiB pages of 32-byte commands
# its-baser-page-size-64k
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -207,7 +207,7 @@
let size = match page {
PageSize::K4 => 0b00,
PageSize::K16 => 0b01,
- PageSize::K64 => 0b10,
+ PageSize::K64 => 0b11,
};
Some(VALID | CACHED | at.get() | size << 8 | (pages - 1) as u64)
}
# its-baser-not-valid
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -209,7 +209,7 @@
PageSize::K16 => 0b01,
PageSize::K64 => 0b10,
};
- Some(VALID | CACHED | at.get() | size << 8 | (pages - 1) as u64)
+ Some(CACHED | at.get() | size << 8 | (pages - 1) as u64)
}
/// The ITS's command queue: `pages` 4 KiB pages of 32-byte commands
# its-cache-field
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -193,7 +193,7 @@
/// `InnerCache` `0b111`, read-allocate write-allocate write-back, with
/// `OuterCache` zero, as the inner; `Shareability` [11:10] `0b01`, inner
/// shareable. `GITS_BASER<n>` and `GITS_CBASER` hold them at the same bits.
-const CACHED: u64 = 0b111 << 59 | 0b01 << 10;
+const CACHED: u64 = 0b111 << 56 | 0b01 << 10;
const VALID: u64 = 1 << 63;
/// `GITS_BASER<n>` for a flat table of `pages` pages of `page` at `at`:
# its-queue-full-is-empty
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -259,6 +259,6 @@
/// One more command would make the writer equal the reader, which reads
/// as empty: the queue holds one command fewer than its bytes do.
pub const fn is_full(self, writer: u32, reader: u32) -> bool {
- self.after(writer) == reader
+ writer == reader && false
}
}
# its-queue-no-wrap
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -248,7 +248,7 @@
/// The offset after `offset`, wrapping at the queue's end.
pub const fn after(self, offset: u32) -> u32 {
- (self.offset(offset as u64) + 32) % self.bytes
+ self.offset(offset as u64) + 32
}
/// The ITS has read every command: the two offsets are equal.
# its-queue-after-overflows
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -248,7 +248,7 @@
/// The offset after `offset`, wrapping at the queue's end.
pub const fn after(self, offset: u32) -> u32 {
- (self.offset(offset as u64) + 32) % self.bytes
+ (offset + 32) % self.bytes
}
/// The ITS has read every command: the two offsets are equal.
# its-queue-offset-field
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -243,7 +243,7 @@
/// The byte offset an offset register names: its `Offset` field alone,
/// and inside the queue whatever the ITS wrote there.
pub const fn offset(self, register: u64) -> u32 {
- (register & 0xF_FFE0) as u32 % self.bytes
+ (register & 0xF_FFFF) as u32 % self.bytes
}
/// The offset after `offset`, wrapping at the queue's end.
# its-queue-offset-unbounded
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -243,7 +243,7 @@
/// The byte offset an offset register names: its `Offset` field alone,
/// and inside the queue whatever the ITS wrote there.
pub const fn offset(self, register: u64) -> u32 {
- (register & 0xF_FFE0) as u32 % self.bytes
+ (register & 0xF_FFE0) as u32
}
/// The offset after `offset`, wrapping at the queue's end.
# its-cbaser-size
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -237,7 +237,7 @@
/// `Physical_Address` [51:12] with its low four bits zero, `Size` [7:0]
/// the pages minus one.
pub const fn cbaser(self, at: Phys<16>) -> u64 {
- VALID | CACHED | at.get() | (self.bytes / 4096 - 1) as u64
+ VALID | CACHED | at.get() | (self.bytes / 4096) as u64 & 0xFF
}
/// The byte offset an offset register names: its `Offset` field alone,
# its-phys-unaligned
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -31,7 +31,7 @@
impl<const ALIGN: u32> Phys<ALIGN> {
pub const fn new(address: u64) -> Option<Self> {
- if address >> 48 == 0 && address & ((1 << ALIGN) - 1) == 0 {
+ if address >> 48 == 0 {
Some(Self(address))
} else {
None
# its-phys-past-48
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -31,7 +31,7 @@
impl<const ALIGN: u32> Phys<ALIGN> {
pub const fn new(address: u64) -> Option<Self> {
- if address >> 48 == 0 && address & ((1 << ALIGN) - 1) == 0 {
+ if address & ((1 << ALIGN) - 1) == 0 {
Some(Self(address))
} else {
None
# lpi-below-8192
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -79,7 +79,7 @@
/// `intid` as an LPI of this space.
pub const fn lpi(self, intid: u32) -> Option<Lpi> {
- if intid >= FIRST && intid >> self.id_bits == 0 {
+ if intid >> self.id_bits == 0 {
Some(Lpi(intid))
} else {
None
# lpi-past-space
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -79,7 +79,7 @@
/// `intid` as an LPI of this space.
pub const fn lpi(self, intid: u32) -> Option<Lpi> {
- if intid >= FIRST && intid >> self.id_bits == 0 {
+ if intid >= FIRST {
Some(Lpi(intid))
} else {
None
# lpi-config-res1
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -52,7 +52,7 @@
/// One LPI's byte in the configuration table (Table 5-1): the priority's
/// upper six bits in [7:2], bit [1] RES1, and the enable in bit [0].
pub const fn configuration(priority: u8, enabled: bool) -> u8 {
- priority & 0xFC | 0b10 | enabled as u8
+ priority & 0xFC | enabled as u8
}
/// The INTIDs of `id_bits` bits the tables are laid out for.
# lpi-config-priority-bits
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -52,7 +52,7 @@
/// One LPI's byte in the configuration table (Table 5-1): the priority's
/// upper six bits in [7:2], bit [1] RES1, and the enable in bit [0].
pub const fn configuration(priority: u8, enabled: bool) -> u8 {
- priority & 0xFC | 0b10 | enabled as u8
+ priority | 0b10 | enabled as u8
}
/// The INTIDs of `id_bits` bits the tables are laid out for.
# lpi-config-index
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -39,7 +39,7 @@
/// Where its byte is in the configuration table: the table's first byte
/// is INTID 8192's (§5.1.1).
pub const fn configuration_index(self) -> usize {
- (self.0 - FIRST) as usize
+ self.0 as usize
}
/// Where its bit is in a pending table, which is indexed by the INTID
# lpi-pending-from-8192
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -45,7 +45,7 @@
/// Where its bit is in a pending table, which is indexed by the INTID
/// itself: the byte, and the bit in it (§5.1.2).
pub const fn pending_bit(self) -> (usize, u8) {
- ((self.0 / 8) as usize, (self.0 % 8) as u8)
+ (((self.0 - FIRST) / 8) as usize, (self.0 % 8) as u8)
}
}
# lpi-pending-bytes
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -93,7 +93,7 @@
/// One bit for every INTID, the first 8192 included.
pub const fn pending_bytes(self) -> usize {
- (1 << self.id_bits) / 8
+ ((1 << self.id_bits) - FIRST as usize) / 8
}
/// `GICR_PROPBASER` (§12.11.33) for the configuration table at `table`:
# lpi-config-bytes
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -88,7 +88,7 @@
/// One byte for every LPI.
pub const fn configuration_bytes(self) -> usize {
- (1 << self.id_bits) - FIRST as usize
+ 1 << self.id_bits
}
/// One bit for every INTID, the first 8192 included.
# lpi-space-floor
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -70,7 +70,7 @@
/// `None` below 14 bits, which reach no LPI, and above the 24 that keep
/// the configuration table within 16 MiB.
pub const fn new(id_bits: u8) -> Option<Self> {
- if id_bits >= 14 && id_bits <= 24 {
+ if id_bits <= 24 {
Some(Self { id_bits })
} else {
None
# lpi-space-ceiling
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -70,7 +70,7 @@
/// `None` below 14 bits, which reach no LPI, and above the 24 that keep
/// the configuration table within 16 MiB.
pub const fn new(id_bits: u8) -> Option<Self> {
- if id_bits >= 14 && id_bits <= 24 {
+ if id_bits >= 14 && id_bits <= 31 {
Some(Self { id_bits })
} else {
None
# lpi-propbaser-idbits
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -99,7 +99,7 @@
/// `GICR_PROPBASER` (§12.11.33) for the configuration table at `table`:
/// `Physical_Address` [51:12] and `IDbits` [4:0], the bits minus one.
pub const fn propbaser(self, table: Phys<12>) -> u64 {
- CACHED | table.get() | (self.id_bits - 1) as u64
+ CACHED | table.get() | self.id_bits as u64
}
}
# lpi-pendbaser-not-zeroed
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -107,5 +107,5 @@
/// all zeroes: `Physical_Address` [51:16], and `PTZ` [62], which says so and
/// lets the redistributor not read it.
pub const fn pendbaser(table: Phys<16>) -> u64 {
- 1 << 62 | CACHED | table.get()
+ CACHED | table.get()
}
# lpi-cache-field
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -64,7 +64,7 @@
/// `InnerCache` [9:7] `0b111`, read-allocate write-allocate write-back, with
/// `OuterCache` [58:56] zero, as the inner; `Shareability` [11:10] `0b01`,
/// inner shareable. Both base registers hold them at the same bits.
-const CACHED: u64 = 0b111 << 7 | 0b01 << 10;
+const CACHED: u64 = 0b111 << 8 | 0b01 << 10;
impl Space {
/// `None` below 14 bits, which reach no LPI, and above the 24 that keep
# lpi-processor-number
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -24,7 +24,7 @@
/// `GICR_TYPER.Processor_Number` [23:8]: how an ITS whose `GITS_TYPER.PTA`
/// is clear names this redistributor.
pub const fn processor_number(typer: u64) -> u16 {
- (typer >> 8) as u16
+ (typer >> 16) as u16
}
/// An LPI's INTID, inside the space it was made in: [`Space::lpi`]. |
|
Review of #798 at Oracles read for this review, fetched from Arm's documentation service: IHI 0070 H.a, IHI 0069 H.b, and DEN 0049 issues E.b, E.c, E.d, E.e, E.f and E.g. No renderer here either, so figures were read as labels with page coordinates, independently of the implementer's extraction. No other kernel's source was read. Growth. BLOCKER
NOTE
Checked and found right
What the landing head must show
SEND BACK |
|
Three corrections to the round-1 review above, from its author's own report to the orchestrator; none moves the verdict:
|
…795), into the IORT decode and the SMMUv3 and ITS encodings Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
…ut size bounds what it is given, and the MADT is main's again Round 2 of the IORT decode and the SMMUv3 and ITS encodings, answering the review of 286536f. toyos-acpi. An SMMUv3 node's own DeviceID mapping is the one its DeviceID mapping index (offset 64) names: where Table 14's bit 4 says the index is valid from node revision 5, and before it wherever one of the four control interrupts has no GSIV, as DEN 0049 E.d words it. That entry's input base and length are not read, and it routes no stream. A single-mapping flag on any other entry refuses the table by name. An output reference is followed by the route that needs it and no longer by the open, which walked the nodes once per mapping: opening reads each node and mapping once, a route walks the nodes three times at most. The MADT's MSI controllers are gone, and madt.rs is main's byte for byte. The node's PRI GSIV is not answered, and its flag is named for what it is, an override. toyos-phys, new: the one Phys<ALIGN> toyos-smmu and toyos-its each declared. toyos-smmu. Every address the unit is given is held to IDR5.OAS: the stream table and both queues by their whole extent, S1ContextPtr, TTB0, a next table and a leaf's output. Ste and Cd hold their words privately. The descriptors, the MAIR and PXN are toyos-bootmap's. The queues are two types made by the unit: Commands, and Events, whose `after` writes OVACKFLG as OVFLG was read. probe takes the IORT's override and refuses a unit that is not coherent. Signal::Sev and CMD_CFGI_CD are gone. toyos-its. An event, a collection and an LPI are types: an event of its device's EventBits, a collection of what GITS_TYPER (HCC, CCT, CIL, CIDbits) and the collection table hold, an LPI of a layout GICD_TYPER bounds in a redistributor whose GICR_PROPBASER read it back. The command queue's emptiness and fullness take the registers and mask them. A table register is a Backing that sizes its own pages. GITS_CTLR.Quiescent, HCC as a public field, the pending bit and the two redistributor offsets the kernel already declares are gone. What still has a second declaration in kernel/ is recorded in issues/the-smmuv3-and-its-crates-declare-what-the-aarch64-kernel-also-declares.md. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01RvnWQFcMuGqTHYhvSnTe8A
|
Round 2, answering the review of BLOCKER
NOTE
What the review could not verify
The body's table says, position by position, which of a field heading, a table row, a figure's label coordinates or a second place in prose each reading rests on. Two things the round found
|
|
The negative control for the two findings whose tests the review named, round 2: the patch below, which adds tests and nothing else, applied to the reviewed head The patch (tests only)diff --git a/toyos-acpi/tests/iort.rs b/toyos-acpi/tests/iort.rs
index da1d0a5cd..3632eec77 100644
--- a/toyos-acpi/tests/iort.rs
+++ b/toyos-acpi/tests/iort.rs
@@ -448,6 +448,74 @@ fn a_single_mapping_is_the_smmus_own_message_and_never_a_root_complexs() {
);
}
+/// An SMMUv3 node of `revision` at `0x0905_0000` with Table 13's flags (24),
+/// its event, PRI, GERR and sync GSIVs (44..60) and its DeviceID mapping
+/// index (64).
+fn smmu_with(revision: u8, flags: u32, gsivs: [u32; 4], index: u32, mappings: &[[u32; 5]]) -> Vec<u8> {
+ let mut fields = vec![0u8; 52];
+ fields[..8].copy_from_slice(&0x0905_0000u64.to_le_bytes());
+ fields[8..12].copy_from_slice(&flags.to_le_bytes());
+ for (i, gsiv) in gsivs.iter().enumerate() {
+ fields[28 + 4 * i..32 + 4 * i].copy_from_slice(&gsiv.to_le_bytes());
+ }
+ fields[48..52].copy_from_slice(&index.to_le_bytes());
+ node(4, revision, &fields, mappings)
+}
+
+/// `virt`'s four GSIVs: every control interrupt wired.
+const WIRED: [u32; 4] = [106, 107, 109, 108];
+/// Table 14, bit 4: `DeviceID mapping index valid`.
+const INDEX_VALID: u32 = 1 << 4;
+
+/// An ITS of id 7, `smmu`, and a root complex sending requesters
+/// `0x00..=0xff` to it as the same streams.
+fn behind(smmu: Vec<u8>) -> Vec<u8> {
+ table(5, &[its(7), smmu, root_complex(0, &[[0, 0xff, 0, SMMU_AT, 0]])])
+}
+
+/// Where the SMMUv3's own node sends stream 8.
+fn onward(table: &[u8]) -> Option<ItsDevice> {
+ match route(table, 0, 8) {
+ Ok(Route::Translated { stream: 8, its, .. }) => its,
+ other => panic!("requester 8 is stream 8 of the SMMUv3: {other:?}"),
+ }
+}
+
+#[test]
+fn the_mapping_a_revision_5_smmu_indexes_is_the_units_own_and_routes_no_stream() {
+ // An input base and length no range holds: they are not the table's to judge.
+ let wide = behind(smmu_with(5, INDEX_VALID, WIRED, 0, &[[0xffff_ffff, 0xffff_ffff, 0x30, ITS_AT, 0]]));
+ assert_eq!(refusal(&wide), None);
+ assert_eq!(onward(&wide), None);
+ // And ones that would hold the stream: the entry is the unit's DeviceID and no stream's.
+ let plausible = behind(smmu_with(5, INDEX_VALID, WIRED, 0, &[[0, 0xffff, 0x30, ITS_AT, 0]]));
+ assert_eq!(onward(&plausible), None);
+ // The index picks the entry, and the other one still routes.
+ let second = smmu_with(5, INDEX_VALID, WIRED, 1, &[[0, 0xff, 0x100, ITS_AT, 0], [0, 0xffff, 0x30, ITS_AT, 0]]);
+ assert_eq!(onward(&behind(second)), Some(ItsDevice { its: 7, device: 0x108 }));
+ // Flag clear, the index is ignored whatever the GSIVs say.
+ let ignored = behind(smmu_with(5, 0, [0; 4], 0, &[[0, 0xff, 0x100, ITS_AT, 0]]));
+ assert_eq!(onward(&ignored), Some(ItsDevice { its: 7, device: 0x108 }));
+}
+
+#[test]
+fn a_revision_4_smmu_indexes_its_own_mapping_whenever_a_control_interrupt_is_not_wired() {
+ for unwired in 0..4 {
+ let mut gsivs = WIRED;
+ gsivs[unwired] = 0;
+ let own = behind(smmu_with(4, 0, gsivs, 0, &[[0xffff_ffff, 0xffff_ffff, 0x30, ITS_AT, 0]]));
+ assert_eq!(refusal(&own), None, "GSIV {unwired} zero");
+ assert_eq!(onward(&own), None, "GSIV {unwired} zero");
+ let plausible = behind(smmu_with(4, 0, gsivs, 0, &[[0, 0xffff, 0x30, ITS_AT, 0]]));
+ assert_eq!(onward(&plausible), None, "GSIV {unwired} zero");
+ }
+ // Every one wired, as on `virt`: the field is ignored, and bit 4 of the flags is reserved here.
+ for flags in [0, INDEX_VALID] {
+ let wired = behind(smmu_with(4, flags, WIRED, 0, &[[0, 0xff, 0x100, ITS_AT, 0]]));
+ assert_eq!(onward(&wired), Some(ItsDevice { its: 7, device: 0x108 }));
+ }
+}
+
#[test]
fn an_its_group_of_other_than_one_its_is_refused() {
for count in [0u32, 2] {
diff --git a/toyos-smmu/tests/encodings.rs b/toyos-smmu/tests/encodings.rs
index 2ede94eac..512313193 100644
--- a/toyos-smmu/tests/encodings.rs
+++ b/toyos-smmu/tests/encodings.rs
@@ -278,6 +278,18 @@ fn a_queue_is_inside_the_units_size_and_aligned_to_its_own() {
assert_eq!((small.command_queue(low, 5), small.event_queue(low, 5)), (None, None));
}
+/// §6.3.24: the bits of `ADDR` above `IDR5.OAS` are RES0, and a unit need not
+/// store them, so it would read its table or queue at the address without
+/// them.
+#[test]
+fn a_table_or_queue_past_the_units_output_size_is_refused() {
+ let unit = idr(&[], &[(20, 16, 19)], &[(2, 0, 0b000)]).expect("a unit of 32 output bits");
+ let past = 1u64 << 32;
+ assert_eq!(unit.stream_table(Phys::new(past).unwrap(), 0), None);
+ assert_eq!(unit.command_queue(Phys::new(past).unwrap(), 0), None);
+ assert_eq!(unit.event_queue(Phys::new(past).unwrap(), 0), None);
+}
+
// --- §3.5.1: the queues' indexes --------------------------------------------
/// Against a count kept beside it: empty exactly at zero entries, fullThe log at 286536f |
|
Mutations at f8022b7, round 2, of The patches# iort-table-revision
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -188,7 +188,7 @@
let table = find_table(phys, rsdp_addr, b"IORT", IORT_NEEDED)?;
let short = TableError::Length { declared: table.len() as u32, needed: IORT_NEEDED };
let revision = table.byte(SDT_REVISION).ok_or(short)?;
- if !REVISIONS.contains(&revision) {
+ if false {
return Err(IortRefused::Revision(revision));
}
let nodes = table.u32_at(NODE_COUNT).ok_or(short)?;
# iort-node-array-floor
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -193,7 +193,7 @@
}
let nodes = table.u32_at(NODE_COUNT).ok_or(short)?;
let offset = table.u32_at(NODE_ARRAY).ok_or(short)?;
- if (offset as usize) < IORT_NEEDED {
+ if false {
return Err(IortRefused::NodeArray { offset });
}
let iort = Iort { table, nodes, array: offset as usize };
# iort-node-past-table
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -311,7 +311,7 @@
SMMUV3 => SMMU_LEN,
_ => NODE_HEADER,
};
- if len < floor || at + len > t.len() {
+ if len < floor {
return Err(IortRefused::Node { at, declared: len });
}
Ok(Raw { at, kind, len, revision, mappings, array })
# iort-node-too-short
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -311,7 +311,7 @@
SMMUV3 => SMMU_LEN,
_ => NODE_HEADER,
};
- if len < floor || at + len > t.len() {
+ if at + len > t.len() {
return Err(IortRefused::Node { at, declared: len });
}
Ok(Raw { at, kind, len, revision, mappings, array })
# iort-node-revision
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -367,7 +367,7 @@
Node::RootComplex { segment: t.u32_at(at + RC_SEGMENT).ok_or(short)? }
}
SMMUV3 => {
- revised(4..=5)?;
+ revised(0..=255)?;
// Event, PRI, GERR, sync: the PRI queue is not used, and its GSIV not answered.
let gsiv = |i: usize| t.u32_at(at + SMMU_GSIVS + 4 * i).map(NonZeroU32::new).ok_or(short);
Node::Smmuv3(Smmuv3 {
# iort-root-revision
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -363,7 +363,7 @@
Node::Its { id: t.u32_at(at + NODE_HEADER + 4).ok_or(short)? }
}
ROOT_COMPLEX => {
- revised(3..=4)?;
+ revised(0..=255)?;
Node::RootComplex { segment: t.u32_at(at + RC_SEGMENT).ok_or(short)? }
}
SMMUV3 => {
# iort-its-revision
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -355,7 +355,7 @@
};
Ok(match kind {
ITS => {
- revised(1..=1)?;
+ revised(0..=255)?;
let count = t.u32_at(at + NODE_HEADER).ok_or(short)?;
if count != 1 {
return Err(IortRefused::ItsGroup { at, count });
# iort-array-over-fields
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -395,7 +395,7 @@
};
let Raw { at, mappings: count, array: offset, .. } = raw;
let end = u64::from(offset) + u64::from(count) * MAPPING as u64;
- let misplaced = (offset as usize) < fields || end > raw.len as u64;
+ let misplaced = end > raw.len as u64;
if count != 0 && (misplaced || matches!(node, Node::Its { .. })) {
return Err(IortRefused::Mappings { at, count, offset });
}
# iort-root-rev4-fields
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -390,7 +390,7 @@
(Node::Other(_), _) => return Ok(()),
(Node::Its { .. }, _) => ITS_LEN,
(Node::RootComplex { .. }, 3) => 36,
- (Node::RootComplex { .. }, _) => 40,
+ (Node::RootComplex { .. }, _) => 36,
(Node::Smmuv3(_), _) => SMMU_LEN,
};
let Raw { at, mappings: count, array: offset, .. } = raw;
# iort-array-past-node
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -395,7 +395,7 @@
};
let Raw { at, mappings: count, array: offset, .. } = raw;
let end = u64::from(offset) + u64::from(count) * MAPPING as u64;
- let misplaced = (offset as usize) < fields || end > raw.len as u64;
+ let misplaced = (offset as usize) < fields;
if count != 0 && (misplaced || matches!(node, Node::Its { .. })) {
return Err(IortRefused::Mappings { at, count, offset });
}
# iort-its-with-array
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -396,7 +396,7 @@
let Raw { at, mappings: count, array: offset, .. } = raw;
let end = u64::from(offset) + u64::from(count) * MAPPING as u64;
let misplaced = (offset as usize) < fields || end > raw.len as u64;
- if count != 0 && (misplaced || matches!(node, Node::Its { .. })) {
+ if count != 0 && (misplaced) {
return Err(IortRefused::Mappings { at, count, offset });
}
let own = self.own(raw);
# iort-range-wraps
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -406,7 +406,7 @@
return Err(IortRefused::SingleMapping { at });
}
for base in [mapping.input, mapping.output] {
- if base.checked_add(mapping.span).is_none() {
+ if false {
return Err(IortRefused::Range { at, base, last: mapping.span });
}
}
# iort-smmu-onward-any-kind
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -241,7 +241,7 @@
None => None,
Some((mapping, device)) => match self.output(unit, mapping)? {
(_, Node::Its { id: its }) => Some(ItsDevice { its, device }),
- _ => return Err(IortRefused::Output { at: unit.at, reference: mapping.reference }),
+ _ => None,
},
};
Ok(Route::Translated { smmu, stream: id, its })
# iort-root-output-any-kind
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -246,7 +246,7 @@
};
Ok(Route::Translated { smmu, stream: id, its })
}
- _ => Err(IortRefused::Output { at: root.at, reference: mapping.reference }),
+ _ => Ok(Route::Unmapped),
}
}
# iort-output-mid-node
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -335,7 +335,7 @@
let refused = IortRefused::Output { at: from.at, reference: mapping.reference };
for raw in self.raw_nodes() {
let raw = raw?;
- if raw.at == mapping.reference as usize {
+ if raw.at <= mapping.reference as usize && raw.at + raw.len > mapping.reference as usize {
return Ok((raw, self.decode(raw)?));
}
}
# iort-single-accepted
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -402,7 +402,7 @@
let own = self.own(raw);
for index in (0..count).filter(|index| Some(*index) != own) {
let mapping = self.mapping(raw, index).ok_or(IortRefused::Mappings { at, count, offset })?;
- if mapping.single {
+ if false {
return Err(IortRefused::SingleMapping { at });
}
for base in [mapping.input, mapping.output] {
# iort-own-routes
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -274,7 +274,7 @@
/// The mappings of `raw` that hold `id`, each with the ID it puts out.
fn hits(&self, raw: Raw, id: u32) -> impl Iterator<Item = (Mapping, u32)> + '_ {
let own = self.own(raw);
- (0..raw.mappings).filter(move |index| Some(*index) != own).filter_map(move |index| {
+ (0..raw.mappings).filter(move |index| Some(*index) != own || true).filter_map(move |index| {
let mapping = self.mapping(raw, index)?;
Some((mapping, mapping.maps(id)?))
})
# iort-own-judged
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -400,7 +400,7 @@
return Err(IortRefused::Mappings { at, count, offset });
}
let own = self.own(raw);
- for index in (0..count).filter(|index| Some(*index) != own) {
+ for index in (0..count).filter(|index| Some(*index) != own || true) {
let mapping = self.mapping(raw, index).ok_or(IortRefused::Mappings { at, count, offset })?;
if mapping.single {
return Err(IortRefused::SingleMapping { at });
# iort-index-flag-bit
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -59,7 +59,7 @@
/// Table 14, bit 0: `COHACC override`.
const SMMU_COHACC: u32 = 1 << 0;
/// Table 14, bit 4, from node revision 5: `DeviceID mapping index valid`.
-const SMMU_INDEXED: u32 = 1 << 4;
+const SMMU_INDEXED: u32 = 1 << 3;
/// Why an IORT cannot be used. `at` is a node's offset in the table.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
# iort-index-offset
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -54,7 +54,7 @@
const SMMU_BASE: usize = 16;
const SMMU_FLAGS: usize = 24;
const SMMU_GSIVS: usize = 44;
-const SMMU_INDEX: usize = 64;
+const SMMU_INDEX: usize = 60;
const SMMU_LEN: usize = 68;
/// Table 14, bit 0: `COHACC override`.
const SMMU_COHACC: u32 = 1 << 0;
# iort-rev4-ignores-index
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -262,7 +262,7 @@
let indexed = if raw.revision >= 5 {
t.u32_at(raw.at + SMMU_FLAGS)? & SMMU_INDEXED != 0
} else {
- (0..4).any(|i| t.u32_at(raw.at + SMMU_GSIVS + 4 * i) == Some(0))
+ false
};
if indexed {
t.u32_at(raw.at + SMMU_INDEX)
# iort-rev4-all-unwired
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -262,7 +262,7 @@
let indexed = if raw.revision >= 5 {
t.u32_at(raw.at + SMMU_FLAGS)? & SMMU_INDEXED != 0
} else {
- (0..4).any(|i| t.u32_at(raw.at + SMMU_GSIVS + 4 * i) == Some(0))
+ (0..4).all(|i| t.u32_at(raw.at + SMMU_GSIVS + 4 * i) == Some(0))
};
if indexed {
t.u32_at(raw.at + SMMU_INDEX)
# iort-rev4-three-gsivs
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -262,7 +262,7 @@
let indexed = if raw.revision >= 5 {
t.u32_at(raw.at + SMMU_FLAGS)? & SMMU_INDEXED != 0
} else {
- (0..4).any(|i| t.u32_at(raw.at + SMMU_GSIVS + 4 * i) == Some(0))
+ (0..3).any(|i| t.u32_at(raw.at + SMMU_GSIVS + 4 * i) == Some(0))
};
if indexed {
t.u32_at(raw.at + SMMU_INDEX)
# iort-rev4-by-flag
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -259,7 +259,7 @@
if raw.kind != SMMUV3 {
return None;
}
- let indexed = if raw.revision >= 5 {
+ let indexed = if raw.revision >= 4 {
t.u32_at(raw.at + SMMU_FLAGS)? & SMMU_INDEXED != 0
} else {
(0..4).any(|i| t.u32_at(raw.at + SMMU_GSIVS + 4 * i) == Some(0))
# iort-rev5-by-gsiv
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -259,7 +259,7 @@
if raw.kind != SMMUV3 {
return None;
}
- let indexed = if raw.revision >= 5 {
+ let indexed = if raw.revision >= 6 {
t.u32_at(raw.at + SMMU_FLAGS)? & SMMU_INDEXED != 0
} else {
(0..4).any(|i| t.u32_at(raw.at + SMMU_GSIVS + 4 * i) == Some(0))
# iort-own-on-any-node
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -256,7 +256,7 @@
/// The entry's input base and length are not read.
fn own(&self, raw: Raw) -> Option<u32> {
let t = &self.table;
- if raw.kind != SMMUV3 {
+ if false {
return None;
}
let indexed = if raw.revision >= 5 {
# iort-open-follows-references
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -405,6 +405,7 @@
if mapping.single {
return Err(IortRefused::SingleMapping { at });
}
+ self.output(raw, mapping)?;
for base in [mapping.input, mapping.output] {
if base.checked_add(mapping.span).is_none() {
return Err(IortRefused::Range { at, base, last: mapping.span });
# iort-its-group
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -357,7 +357,7 @@
ITS => {
revised(1..=1)?;
let count = t.u32_at(at + NODE_HEADER).ok_or(short)?;
- if count != 1 {
+ if false {
return Err(IortRefused::ItsGroup { at, count });
}
Node::Its { id: t.u32_at(at + NODE_HEADER + 4).ok_or(short)? }
# iort-overlap-root
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -220,7 +220,7 @@
continue;
}
for found in self.hits(raw, rid) {
- if hit.replace((raw, found)).is_some() {
+ if hit.replace((raw, found)).is_some() && false {
return Err(IortRefused::Overlap { id: rid });
}
}
# iort-overlap-smmu
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -233,7 +233,7 @@
(unit, Node::Smmuv3(smmu)) => {
let mut onward = None;
for found in self.hits(unit, id) {
- if onward.replace(found).is_some() {
+ if onward.replace(found).is_some() && false {
return Err(IortRefused::Overlap { id });
}
}
# iort-span-exclusive
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -171,7 +171,7 @@
impl Mapping {
fn maps(&self, id: u32) -> Option<u32> {
// `output + span` was checked not to wrap when the table was opened.
- (id >= self.input && id - self.input <= self.span).then(|| self.output + (id - self.input))
+ (id >= self.input && id - self.input < self.span).then(|| self.output + (id - self.input))
}
}
# iort-output-not-offset
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -171,7 +171,7 @@
impl Mapping {
fn maps(&self, id: u32) -> Option<u32> {
// `output + span` was checked not to wrap when the table was opened.
- (id >= self.input && id - self.input <= self.span).then(|| self.output + (id - self.input))
+ (id >= self.input && id - self.input <= self.span).then(|| self.output.wrapping_add(id))
}
}
# iort-any-segment
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -216,7 +216,7 @@
let mut hit = None;
for raw in self.raw_nodes() {
let raw = raw?;
- if self.decode(raw)? != (Node::RootComplex { segment }) {
+ if !matches!(self.decode(raw)?, Node::RootComplex { .. }) {
continue;
}
for found in self.hits(raw, rid) {
# iort-gsiv-order
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -369,7 +369,7 @@
SMMUV3 => {
revised(4..=5)?;
// Event, PRI, GERR, sync: the PRI queue is not used, and its GSIV not answered.
- let gsiv = |i: usize| t.u32_at(at + SMMU_GSIVS + 4 * i).map(NonZeroU32::new).ok_or(short);
+ let gsiv = |i: usize| t.u32_at(at + SMMU_GSIVS + 4 * (3 - i)).map(NonZeroU32::new).ok_or(short);
Node::Smmuv3(Smmuv3 {
base: t.u64_at(at + SMMU_BASE).ok_or(short)?,
coherent_override: t.u32_at(at + SMMU_FLAGS).ok_or(short)? & SMMU_COHACC != 0,
# iort-gerror-is-pri
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -374,7 +374,7 @@
base: t.u64_at(at + SMMU_BASE).ok_or(short)?,
coherent_override: t.u32_at(at + SMMU_FLAGS).ok_or(short)? & SMMU_COHACC != 0,
event: gsiv(0)?,
- gerror: gsiv(2)?,
+ gerror: gsiv(1)?,
sync: gsiv(3)?,
})
}
# iort-cohacc-bit
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -57,7 +57,7 @@
const SMMU_INDEX: usize = 64;
const SMMU_LEN: usize = 68;
/// Table 14, bit 0: `COHACC override`.
-const SMMU_COHACC: u32 = 1 << 0;
+const SMMU_COHACC: u32 = 1 << 1;
/// Table 14, bit 4, from node revision 5: `DeviceID mapping index valid`.
const SMMU_INDEXED: u32 = 1 << 4;
# iort-segment-offset
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -47,7 +47,7 @@
/// Table 18: memory access properties (16..24), ATS attribute (24..28), PCI
/// segment number (28..32), then the address size limit and, from node
/// revision 4, the PASID capabilities and flags.
-const RC_SEGMENT: usize = 28;
+const RC_SEGMENT: usize = 24;
/// Table 13: base address (16..24), flags (24..28), a reserved word, VATOS
/// (32..40), model (40..44), the event, PRI, GERR and sync GSIVs (44..60),
/// proximity domain (60..64), DeviceID mapping index (64..68).
# iort-smmu-floor
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -55,7 +55,7 @@
const SMMU_FLAGS: usize = 24;
const SMMU_GSIVS: usize = 44;
const SMMU_INDEX: usize = 64;
-const SMMU_LEN: usize = 68;
+const SMMU_LEN: usize = 64;
/// Table 14, bit 0: `COHACC override`.
const SMMU_COHACC: u32 = 1 << 0;
/// Table 14, bit 4, from node revision 5: `DeviceID mapping index valid`.
# iort-untranslated-id
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -229,7 +229,7 @@
return Ok(Route::Unmapped);
};
match self.output(root, mapping)? {
- (_, Node::Its { id: its }) => Ok(Route::Untranslated(ItsDevice { its, device: id })),
+ (_, Node::Its { id: its }) => Ok(Route::Untranslated(ItsDevice { its, device: rid })),
(unit, Node::Smmuv3(smmu)) => {
let mut onward = None;
for found in self.hits(unit, id) { |
|
Mutations at f8022b7, round 2, of The patches# ste-abort-not-valid
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -26,7 +26,7 @@
/// `V` set and `Config` `0b000`: every transaction of the stream is
/// aborted, and no event is recorded for it. An entry of all zeroes
/// aborts too, and records `C_BAD_STE` each time.
- pub const ABORT: Self = Self([STE_V, 0, 0, 0, 0, 0, 0, 0]);
+ pub const ABORT: Self = Self([0, 0, 0, 0, 0, 0, 0, 0]);
/// The stream translated by stage 1 through the one context descriptor
/// at `context`: `S1ContextPtr` [55:6], `S1CDMax` [63:59] zero so a
# ste-bypass
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -14,7 +14,7 @@
/// `V`, bit [0].
const STE_V: u64 = 1 << 0;
/// `Config`, bits [3:1]: `0b101` is stage 1 translate, stage 2 bypass.
-const STE_STAGE1: u64 = 0b101 << 1;
+const STE_STAGE1: u64 = 0b100 << 1;
/// Doubleword 1: `S1CIR` [67:66] and `S1COR` [69:68] `0b01`, write-back
/// read-allocate, and `S1CSH` [71:70] `0b11`, inner shareable — how the unit
/// reads the context descriptor.
# ste-stage2
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -14,7 +14,7 @@
/// `V`, bit [0].
const STE_V: u64 = 1 << 0;
/// `Config`, bits [3:1]: `0b101` is stage 1 translate, stage 2 bypass.
-const STE_STAGE1: u64 = 0b101 << 1;
+const STE_STAGE1: u64 = 0b110 << 1;
/// Doubleword 1: `S1CIR` [67:66] and `S1COR` [69:68] `0b01`, write-back
/// read-allocate, and `S1CSH` [71:70] `0b11`, inner shareable — how the unit
/// reads the context descriptor.
# ste-stalld-bit
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -20,7 +20,7 @@
/// reads the context descriptor.
const STE_CD_CACHED: u64 = 0b01 << 2 | 0b01 << 4 | 0b11 << 6;
/// `S1STALLD`, bit [91].
-const STE_S1STALLD: u64 = 1 << 27;
+const STE_S1STALLD: u64 = 1 << 26;
impl Ste {
/// `V` set and `Config` `0b000`: every transaction of the stream is
# ste-stalld-always
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -38,7 +38,7 @@
if !unit.reaches(context.get(), 64) {
return None;
}
- let stall = if unit.stall_disable() { STE_S1STALLD } else { 0 };
+ let stall = STE_S1STALLD;
Some(Self([STE_V | STE_STAGE1 | context.get(), STE_CD_CACHED | stall, 0, 0, 0, 0, 0, 0]))
}
# ste-stalld-never
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -38,7 +38,7 @@
if !unit.reaches(context.get(), 64) {
return None;
}
- let stall = if unit.stall_disable() { STE_S1STALLD } else { 0 };
+ let stall = 0;
Some(Self([STE_V | STE_STAGE1 | context.get(), STE_CD_CACHED | stall, 0, 0, 0, 0, 0, 0]))
}
# ste-cd-attributes
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -18,7 +18,7 @@
/// Doubleword 1: `S1CIR` [67:66] and `S1COR` [69:68] `0b01`, write-back
/// read-allocate, and `S1CSH` [71:70] `0b11`, inner shareable — how the unit
/// reads the context descriptor.
-const STE_CD_CACHED: u64 = 0b01 << 2 | 0b01 << 4 | 0b11 << 6;
+const STE_CD_CACHED: u64 = 0b01 << 0 | 0b01 << 2 | 0b11 << 4;
/// `S1STALLD`, bit [91].
const STE_S1STALLD: u64 = 1 << 27;
# ste-context-past-output
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -35,7 +35,7 @@
/// no stage 2 field. `None` where the descriptor is past the unit's
/// output size.
pub const fn stage1(context: Phys<6>, unit: &Unit) -> Option<Self> {
- if !unit.reaches(context.get(), 64) {
+ if false {
return None;
}
let stall = if unit.stall_disable() { STE_S1STALLD } else { 0 };
# cd-root-past-output
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -80,7 +80,7 @@
/// leaf written sets its access flag. `None` where the root table is
/// past the unit's output size.
pub const fn new(root: Phys<12>, asid: Asid, unit: &Unit) -> Option<Self> {
- if !unit.reaches(root.get(), 4096) {
+ if false {
return None;
}
let word0 = CD_T0SZ
# cd-ttb1-walked
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -85,7 +85,6 @@
}
let word0 = CD_T0SZ
| CD_WALK
- | CD_EPD1
| CD_V
| unit.ips() << 32
| CD_AA64
# cd-not-valid
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -86,7 +86,6 @@
let word0 = CD_T0SZ
| CD_WALK
| CD_EPD1
- | CD_V
| unit.ips() << 32
| CD_AA64
| CD_FAULTS
# cd-shared-asid-set
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -90,7 +90,6 @@
| unit.ips() << 32
| CD_AA64
| CD_FAULTS
- | CD_ASET
| (asid.get() as u64) << 48;
Some(Self([word0, root.get(), 0, crate::table::MAIR0 as u64, 0, 0, 0, 0]))
}
# cd-raz-wi
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -68,7 +68,7 @@
/// `R` [45] records a translation-related fault and `A` [46] aborts its
/// transaction rather than completing it as read-as-zero, write-ignored;
/// `S` [44] stays clear, so none stalls (§5.5).
-const CD_FAULTS: u64 = 1 << 45 | 1 << 46;
+const CD_FAULTS: u64 = 1 << 45;
/// `ASET`, bit [47]: the ASID is the unit's own and no CPU process's.
const CD_ASET: u64 = 1 << 47;
# cd-unrecorded
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -68,7 +68,7 @@
/// `R` [45] records a translation-related fault and `A` [46] aborts its
/// transaction rather than completing it as read-as-zero, write-ignored;
/// `S` [44] stays clear, so none stalls (§5.5).
-const CD_FAULTS: u64 = 1 << 45 | 1 << 46;
+const CD_FAULTS: u64 = 1 << 46;
/// `ASET`, bit [47]: the ASID is the unit's own and no CPU process's.
const CD_ASET: u64 = 1 << 47;
# cd-stalls
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -68,7 +68,7 @@
/// `R` [45] records a translation-related fault and `A` [46] aborts its
/// transaction rather than completing it as read-as-zero, write-ignored;
/// `S` [44] stays clear, so none stalls (§5.5).
-const CD_FAULTS: u64 = 1 << 45 | 1 << 46;
+const CD_FAULTS: u64 = 1 << 44 | 1 << 45 | 1 << 46;
/// `ASET`, bit [47]: the ASID is the unit's own and no CPU process's.
const CD_ASET: u64 = 1 << 47;
# cd-asid-field
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -91,7 +91,7 @@
| CD_AA64
| CD_FAULTS
| CD_ASET
- | (asid.get() as u64) << 48;
+ | (asid.get() as u64) << 32;
Some(Self([word0, root.get(), 0, crate::table::MAIR0 as u64, 0, 0, 0, 0]))
}
# cd-t0sz
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -53,7 +53,7 @@
pub struct Cd([u64; 8]);
/// `T0SZ`, bits [5:0]: a 48-bit input, walked from level 0.
-const CD_T0SZ: u64 = 64 - crate::table::INPUT_BITS as u64;
+const CD_T0SZ: u64 = crate::table::INPUT_BITS as u64;
/// `TG0` [7:6] zero is the 4 KiB granule; `IR0` [9:8] and `OR0` [11:10]
/// `0b01`, write-back write-allocate, and `SH0` [13:12] `0b11`, inner
/// shareable — how the unit walks the tables; `EPD0` [14] and `ENDI` [15]
# cd-aarch32
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -88,7 +88,6 @@
| CD_EPD1
| CD_V
| unit.ips() << 32
- | CD_AA64
| CD_FAULTS
| CD_ASET
| (asid.get() as u64) << 48;
# cd-ips-field
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -87,7 +87,7 @@
| CD_WALK
| CD_EPD1
| CD_V
- | unit.ips() << 32
+ | unit.ips() << 33
| CD_AA64
| CD_FAULTS
| CD_ASET
# cd-ttb0-word
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -92,7 +92,7 @@
| CD_FAULTS
| CD_ASET
| (asid.get() as u64) << 48;
- Some(Self([word0, root.get(), 0, crate::table::MAIR0 as u64, 0, 0, 0, 0]))
+ Some(Self([word0, 0, root.get(), crate::table::MAIR0 as u64, 0, 0, 0, 0]))
}
/// The descriptor's eight doublewords.
# cd-mair-word
--- a/toyos-smmu/src/config.rs
+++ b/toyos-smmu/src/config.rs
@@ -92,7 +92,7 @@
| CD_FAULTS
| CD_ASET
| (asid.get() as u64) << 48;
- Some(Self([word0, root.get(), 0, crate::table::MAIR0 as u64, 0, 0, 0, 0]))
+ Some(Self([word0, root.get(), crate::table::MAIR0 as u64, 0, 0, 0, 0, 0]))
}
/// The descriptor's eight doublewords.
# leaf-global
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -42,7 +42,7 @@
/// What a device's leaf adds to the loader's: unprivileged, its context's
/// alone, and executable at no level — the loader's memory is executable at
/// EL1, which no device's access is.
-const DEVICES: u64 = AP_UNPRIVILEGED | NOT_GLOBAL | PXN;
+const DEVICES: u64 = AP_UNPRIVILEGED | PXN;
/// What a device may do to memory mapped for it.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
# leaf-privileged-only
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -42,7 +42,7 @@
/// What a device's leaf adds to the loader's: unprivileged, its context's
/// alone, and executable at no level — the loader's memory is executable at
/// EL1, which no device's access is.
-const DEVICES: u64 = AP_UNPRIVILEGED | NOT_GLOBAL | PXN;
+const DEVICES: u64 = NOT_GLOBAL | PXN;
/// What a device may do to memory mapped for it.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
# leaf-executable-at-el1
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -42,7 +42,7 @@
/// What a device's leaf adds to the loader's: unprivileged, its context's
/// alone, and executable at no level — the loader's memory is executable at
/// EL1, which no device's access is.
-const DEVICES: u64 = AP_UNPRIVILEGED | NOT_GLOBAL | PXN;
+const DEVICES: u64 = AP_UNPRIVILEGED | NOT_GLOBAL;
/// What a device may do to memory mapped for it.
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
# leaf-ap1-bit
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -31,7 +31,7 @@
/// `AP[1]`, bit [6]: an unprivileged access is permitted. A PCIe transaction
/// without a PASID prefix is unprivileged (IHI 0070 §13.7), so a leaf without
/// it is one no device reaches.
-const AP_UNPRIVILEGED: u64 = 1 << 6;
+const AP_UNPRIVILEGED: u64 = 1 << 5;
/// `AP[2]`, bit [7]: read-only.
const AP_READ_ONLY: u64 = 1 << 7;
/// `nG`, bit [11]: the translation is its context's alone. A leaf without it
# leaf-ng-bit
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -37,7 +37,7 @@
/// `nG`, bit [11]: the translation is its context's alone. A leaf without it
/// is global, cached for every ASID of the regime and so for every domain,
/// and no invalidation by ASID removes it.
-const NOT_GLOBAL: u64 = 1 << 11;
+const NOT_GLOBAL: u64 = 1 << 12;
/// What a device's leaf adds to the loader's: unprivileged, its context's
/// alone, and executable at no level — the loader's memory is executable at
# leaf-read-is-writable
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -97,7 +97,7 @@
let (tables, size, output, descriptor) = match leaf {
Leaf::Memory(memory, access) => {
let access = match access {
- Access::Read => AP_READ_ONLY,
+ Access::Read => 0,
Access::ReadWrite => 0,
};
(3, 1u64 << 21, memory.get(), block(memory.get(), Cache::Memory) | DEVICES | access)
# leaf-write-is-read-only
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -98,7 +98,7 @@
Leaf::Memory(memory, access) => {
let access = match access {
Access::Read => AP_READ_ONLY,
- Access::ReadWrite => 0,
+ Access::ReadWrite => AP_READ_ONLY,
};
(3, 1u64 << 21, memory.get(), block(memory.get(), Cache::Memory) | DEVICES | access)
}
# leaf-memory-as-device
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -100,7 +100,7 @@
Access::Read => AP_READ_ONLY,
Access::ReadWrite => 0,
};
- (3, 1u64 << 21, memory.get(), block(memory.get(), Cache::Memory) | DEVICES | access)
+ (3, 1u64 << 21, memory.get(), block(memory.get(), Cache::Device) | DEVICES | access)
}
Leaf::Doorbell(register) => (4, 1u64 << 12, register.get(), page(register.get(), Cache::Device) | DEVICES),
};
# doorbell-as-block
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -102,7 +102,7 @@
};
(3, 1u64 << 21, memory.get(), block(memory.get(), Cache::Memory) | DEVICES | access)
}
- Leaf::Doorbell(register) => (4, 1u64 << 12, register.get(), page(register.get(), Cache::Device) | DEVICES),
+ Leaf::Doorbell(register) => (4, 1u64 << 12, register.get(), block(register.get(), Cache::Device) | DEVICES),
};
if at >> INPUT_BITS != 0 || at & (size - 1) != 0 || !unit.reaches(output, size) {
return None;
# doorbell-as-memory
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -102,7 +102,7 @@
};
(3, 1u64 << 21, memory.get(), block(memory.get(), Cache::Memory) | DEVICES | access)
}
- Leaf::Doorbell(register) => (4, 1u64 << 12, register.get(), page(register.get(), Cache::Device) | DEVICES),
+ Leaf::Doorbell(register) => (4, 1u64 << 12, register.get(), page(register.get(), Cache::Memory) | DEVICES),
};
if at >> INPUT_BITS != 0 || at & (size - 1) != 0 || !unit.reaches(output, size) {
return None;
# doorbell-at-level-2
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -102,7 +102,7 @@
};
(3, 1u64 << 21, memory.get(), block(memory.get(), Cache::Memory) | DEVICES | access)
}
- Leaf::Doorbell(register) => (4, 1u64 << 12, register.get(), page(register.get(), Cache::Device) | DEVICES),
+ Leaf::Doorbell(register) => (3, 1u64 << 12, register.get(), page(register.get(), Cache::Device) | DEVICES),
};
if at >> INPUT_BITS != 0 || at & (size - 1) != 0 || !unit.reaches(output, size) {
return None;
# plan-unaligned
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -104,7 +104,7 @@
}
Leaf::Doorbell(register) => (4, 1u64 << 12, register.get(), page(register.get(), Cache::Device) | DEVICES),
};
- if at >> INPUT_BITS != 0 || at & (size - 1) != 0 || !unit.reaches(output, size) {
+ if at >> INPUT_BITS != 0 || !unit.reaches(output, size) {
return None;
}
const fn index(at: u64, level: u32) -> usize {
# plan-past-input
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -104,7 +104,7 @@
}
Leaf::Doorbell(register) => (4, 1u64 << 12, register.get(), page(register.get(), Cache::Device) | DEVICES),
};
- if at >> INPUT_BITS != 0 || at & (size - 1) != 0 || !unit.reaches(output, size) {
+ if at & (size - 1) != 0 || !unit.reaches(output, size) {
return None;
}
const fn index(at: u64, level: u32) -> usize {
# plan-past-output
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -104,7 +104,7 @@
}
Leaf::Doorbell(register) => (4, 1u64 << 12, register.get(), page(register.get(), Cache::Device) | DEVICES),
};
- if at >> INPUT_BITS != 0 || at & (size - 1) != 0 || !unit.reaches(output, size) {
+ if at >> INPUT_BITS != 0 || at & (size - 1) != 0 {
return None;
}
const fn index(at: u64, level: u32) -> usize {
# plan-index-shift
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -108,7 +108,7 @@
return None;
}
const fn index(at: u64, level: u32) -> usize {
- (at >> (39 - 9 * level) & 0x1FF) as usize
+ (at >> (38 - 9 * level) & 0x1FF) as usize
}
Some(Path { indices: [index(at, 0), index(at, 1), index(at, 2), index(at, 3)], tables, descriptor })
}
# plan-index-width
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -108,7 +108,7 @@
return None;
}
const fn index(at: u64, level: u32) -> usize {
- (at >> (39 - 9 * level) & 0x1FF) as usize
+ (at >> (39 - 9 * level) & 0xFF) as usize
}
Some(Path { indices: [index(at, 0), index(at, 1), index(at, 2), index(at, 3)], tables, descriptor })
}
# entry-page-as-table
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -129,7 +129,7 @@
pub const fn entry(descriptor: u64, level: usize) -> Entry {
if descriptor & VALID == 0 {
Entry::Invalid
- } else if level < LEVELS - 1 && descriptor & TABLE_OR_PAGE != 0 {
+ } else if descriptor & TABLE_OR_PAGE != 0 {
Entry::Table(Phys::of(descriptor))
} else {
Entry::Mapped
# entry-invalid-as-table
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -127,7 +127,7 @@
/// `descriptor` as the walk reads it at `level`: bit [1] names a table above
/// level 3 and a page at it, and a table's address is bits [47:12].
pub const fn entry(descriptor: u64, level: usize) -> Entry {
- if descriptor & VALID == 0 {
+ if descriptor == 0 {
Entry::Invalid
} else if level < LEVELS - 1 && descriptor & TABLE_OR_PAGE != 0 {
Entry::Table(Phys::of(descriptor))
# next-past-output
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -64,7 +64,7 @@
/// hierarchical fields stay clear: the leaf alone decides the access. `None`
/// where the table is past the unit's output size.
pub const fn next(at: Phys<12>, unit: &Unit) -> Option<u64> {
- if unit.reaches(at.get(), 4096) {
+ if true {
Some(table(at.get()))
} else {
None
# mair0-shifted
--- a/toyos-smmu/src/table.rs
+++ b/toyos-smmu/src/table.rs
@@ -22,7 +22,7 @@
/// `CD.MAIR0`, attributes 0 to 3 of the `MAIR` the descriptors' `AttrIndx`
/// names: a [`Cache::Device`] leaf's is Device-nGnRE and a [`Cache::Memory`]
/// leaf's Normal write-back.
-pub const MAIR0: u32 = MAIR as u32;
+pub const MAIR0: u32 = (MAIR >> 8) as u32;
/// Table D8-50 and Table D8-52: bit [0] valid; bit [1] set for a table
/// descriptor and a level 3 page, clear for a block.
# bootmap-mair-order
--- a/toyos-bootmap/src/aarch64.rs
+++ b/toyos-bootmap/src/aarch64.rs
@@ -18,7 +18,7 @@
pub const ATTR_NORMAL_NC: u64 = 2;
/// Each index's attribute byte (D24.2.110), in index order: the value
/// `PAR_EL1.ATTR` also reports a translation's type in.
-pub const ATTRS: [u8; 3] = [0x04, 0xFF, 0x44];
+pub const ATTRS: [u8; 3] = [0xFF, 0x04, 0x44];
/// `MAIR_EL1` whole.
pub const MAIR: u64 = ATTRS[0] as u64 | (ATTRS[1] as u64) << 8 | (ATTRS[2] as u64) << 16;
# bootmap-table-bits
--- a/toyos-bootmap/src/aarch64.rs
+++ b/toyos-bootmap/src/aarch64.rs
@@ -23,7 +23,7 @@
pub const MAIR: u64 = ATTRS[0] as u64 | (ATTRS[1] as u64) << 8 | (ATTRS[2] as u64) << 16;
/// A table descriptor (bits 1:0 = 0b11) naming the next table down.
-const TABLE: u64 = 0b11;
+const TABLE: u64 = 0b01;
/// A block descriptor (bits 1:0 = 0b01) at level 1 or 2.
const BLOCK: u64 = 0b01;
/// `SH` = inner shareable, bits 9:8.
# bootmap-page-bits
--- a/toyos-bootmap/src/aarch64.rs
+++ b/toyos-bootmap/src/aarch64.rs
@@ -38,7 +38,7 @@
const UXN: u64 = 1 << 54;
/// A page descriptor (bits 1:0 = 0b11) at level 3.
-const PAGE: u64 = 0b11;
+const PAGE: u64 = 0b01;
/// A descriptor naming the next table down, at `phys`.
pub const fn table(phys: u64) -> u64 {
# bootmap-block-bits
--- a/toyos-bootmap/src/aarch64.rs
+++ b/toyos-bootmap/src/aarch64.rs
@@ -25,7 +25,7 @@
/// A table descriptor (bits 1:0 = 0b11) naming the next table down.
const TABLE: u64 = 0b11;
/// A block descriptor (bits 1:0 = 0b01) at level 1 or 2.
-const BLOCK: u64 = 0b01;
+const BLOCK: u64 = 0b11;
/// `SH` = inner shareable, bits 9:8.
const INNER_SHAREABLE: u64 = 0b11 << 8;
/// `SH` = outer shareable.
# bootmap-no-access-flag
--- a/toyos-bootmap/src/aarch64.rs
+++ b/toyos-bootmap/src/aarch64.rs
@@ -31,7 +31,7 @@
/// `SH` = outer shareable.
const OUTER_SHAREABLE: u64 = 0b10 << 8;
/// The access flag, bit 10: set, so the first access does not fault.
-const AF: u64 = 1 << 10;
+const AF: u64 = 0;
/// Privileged execute-never, bit 53.
pub const PXN: u64 = 1 << 53;
/// Unprivileged execute-never, bit 54.
# bootmap-memory-shareability
--- a/toyos-bootmap/src/aarch64.rs
+++ b/toyos-bootmap/src/aarch64.rs
@@ -27,7 +27,7 @@
/// A block descriptor (bits 1:0 = 0b01) at level 1 or 2.
const BLOCK: u64 = 0b01;
/// `SH` = inner shareable, bits 9:8.
-const INNER_SHAREABLE: u64 = 0b11 << 8;
+const INNER_SHAREABLE: u64 = 0b10 << 8;
/// `SH` = outer shareable.
const OUTER_SHAREABLE: u64 = 0b10 << 8;
/// The access flag, bit 10: set, so the first access does not fault.
# bootmap-memory-attribute
--- a/toyos-bootmap/src/aarch64.rs
+++ b/toyos-bootmap/src/aarch64.rs
@@ -55,7 +55,7 @@
const fn attributes(cache: Cache) -> u64 {
match cache {
- Cache::Memory => ATTR_NORMAL << 2 | INNER_SHAREABLE | UXN,
+ Cache::Memory => ATTR_NORMAL_NC << 2 | INNER_SHAREABLE | UXN,
Cache::Device => ATTR_DEVICE << 2 | PXN | UXN,
Cache::Scanout => ATTR_NORMAL_NC << 2 | OUTER_SHAREABLE | PXN | UXN,
Cache::Firmware => panic!("AArch64 has no range registers to type memory: its plan types by the map"),
# bootmap-device-executable
--- a/toyos-bootmap/src/aarch64.rs
+++ b/toyos-bootmap/src/aarch64.rs
@@ -56,7 +56,7 @@
const fn attributes(cache: Cache) -> u64 {
match cache {
Cache::Memory => ATTR_NORMAL << 2 | INNER_SHAREABLE | UXN,
- Cache::Device => ATTR_DEVICE << 2 | PXN | UXN,
+ Cache::Device => ATTR_DEVICE << 2 | PXN,
Cache::Scanout => ATTR_NORMAL_NC << 2 | OUTER_SHAREABLE | PXN | UXN,
Cache::Firmware => panic!("AArch64 has no range registers to type memory: its plan types by the map"),
}
# bootmap-pxn-bit
--- a/toyos-bootmap/src/aarch64.rs
+++ b/toyos-bootmap/src/aarch64.rs
@@ -33,7 +33,7 @@
/// The access flag, bit 10: set, so the first access does not fault.
const AF: u64 = 1 << 10;
/// Privileged execute-never, bit 53.
-pub const PXN: u64 = 1 << 53;
+pub const PXN: u64 = 1 << 52;
/// Unprivileged execute-never, bit 54.
const UXN: u64 = 1 << 54;
# bootmap-uxn-bit
--- a/toyos-bootmap/src/aarch64.rs
+++ b/toyos-bootmap/src/aarch64.rs
@@ -35,7 +35,7 @@
/// Privileged execute-never, bit 53.
pub const PXN: u64 = 1 << 53;
/// Unprivileged execute-never, bit 54.
-const UXN: u64 = 1 << 54;
+const UXN: u64 = 1 << 55;
/// A page descriptor (bits 1:0 = 0b11) at level 3.
const PAGE: u64 = 0b11; |
|
Mutations at f8022b7, round 2, of The patches# unit-ips-52
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -217,7 +217,7 @@
40 => 0b010,
42 => 0b011,
44 => 0b100,
- _ => 0b101,
+ _ => 0b110,
}
}
# queue-full-is-empty
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -49,7 +49,7 @@
/// No command can be written: the indexes are equal and the wrap flags
/// differ.
pub const fn is_full(self, prod: u32, cons: u32) -> bool {
- self.0.position(prod) ^ self.0.position(cons) == 1 << self.0.log2size
+ self.0.position(prod) == self.0.position(cons)
}
/// The unit has consumed every command written.
# queue-no-wrap-flag
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -30,7 +30,7 @@
/// The position after `register`'s, wrap flag toggled where it passes
/// the top.
const fn after(self, register: u32) -> u32 {
- self.position(self.position(register) + 1)
+ (self.position(register) + 1) & ((1 << self.log2size) - 1)
}
}
# queue-after-overflows
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -30,7 +30,7 @@
/// The position after `register`'s, wrap flag toggled where it passes
/// the top.
const fn after(self, register: u32) -> u32 {
- self.position(self.position(register) + 1)
+ self.position(register + 1)
}
}
# queue-empty-ignores-wrap
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -24,7 +24,7 @@
/// The indexes and their wrap flags are equal.
const fn is_empty(self, prod: u32, cons: u32) -> bool {
- self.position(prod) == self.position(cons)
+ self.slot(prod) == self.slot(cons)
}
/// The position after `register`'s, wrap flag toggled where it passes
# events-after-clears-the-ack
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -95,7 +95,7 @@
/// `prod` was read with. That acknowledges an overflow seen in `prod`,
/// and no value this answers raises one the unit did not report.
pub const fn after(self, cons: u32, prod: u32) -> u32 {
- self.0.after(cons) | prod & OVERFLOW
+ self.0.after(cons)
}
}
# events-after-never-acks
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -95,7 +95,7 @@
/// `prod` was read with. That acknowledges an overflow seen in `prod`,
/// and no value this answers raises one the unit did not report.
pub const fn after(self, cons: u32, prod: u32) -> u32 {
- self.0.after(cons) | prod & OVERFLOW
+ self.0.after(cons) | cons & OVERFLOW
}
}
# events-overflow-bit
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -65,7 +65,7 @@
}
/// `SMMU_EVENTQ_PROD.OVFLG` and `SMMU_EVENTQ_CONS.OVACKFLG`, bit [31] of each.
-const OVERFLOW: u32 = 1 << 31;
+const OVERFLOW: u32 = 1 << 30;
/// The event queue's indexes, as the driver that consumes from it reads
/// `SMMU_EVENTQ_PROD` and `SMMU_EVENTQ_CONS`: made by
# events-overflowed-by-prod-alone
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -87,7 +87,7 @@
/// Records were dropped on a full queue and that is not yet
/// acknowledged: `OVFLG` differs from `OVACKFLG` (§7.4).
pub const fn overflowed(self, prod: u32, cons: u32) -> bool {
- (prod ^ cons) & OVERFLOW != 0
+ prod & OVERFLOW != 0
}
/// What `SMMU_EVENTQ_CONS` is written with once the record at `cons` is
# cmd-sync-signal-field
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -143,7 +143,7 @@
Signal::None => 0b00,
Signal::Irq => 0b01,
};
- [0x46 | cs << 12, 0]
+ [0x46 | cs << 11, 0]
}
}
}
# cmd-sync-irq-value
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -141,7 +141,7 @@
Self::Sync(signal) => {
let cs = match signal {
Signal::None => 0b00,
- Signal::Irq => 0b01,
+ Signal::Irq => 0b10,
};
[0x46 | cs << 12, 0]
}
# cmd-forget-stream-nonleaf
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -131,7 +131,7 @@
pub const fn words(self) -> [u64; 2] {
match self {
// StreamID [63:32]; Leaf [64].
- Self::ForgetStream(stream) => [0x03 | (stream as u64) << 32, 1],
+ Self::ForgetStream(stream) => [0x03 | (stream as u64) << 32, 0],
// `CMD_CFGI_STE_RANGE` with Range [68:64] of 31.
Self::ForgetAll => [0x04, 31],
// ASID [63:48], VMID [47:32].
# cmd-forget-stream-field
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -131,7 +131,7 @@
pub const fn words(self) -> [u64; 2] {
match self {
// StreamID [63:32]; Leaf [64].
- Self::ForgetStream(stream) => [0x03 | (stream as u64) << 32, 1],
+ Self::ForgetStream(stream) => [0x03 | (stream as u64) << 12, 1],
// `CMD_CFGI_STE_RANGE` with Range [68:64] of 31.
Self::ForgetAll => [0x04, 31],
// ASID [63:48], VMID [47:32].
# cmd-forget-all-range
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -133,7 +133,7 @@
// StreamID [63:32]; Leaf [64].
Self::ForgetStream(stream) => [0x03 | (stream as u64) << 32, 1],
// `CMD_CFGI_STE_RANGE` with Range [68:64] of 31.
- Self::ForgetAll => [0x04, 31],
+ Self::ForgetAll => [0x04, 0],
// ASID [63:48], VMID [47:32].
Self::InvalidateAsid(asid) => [0x11 | (asid.get() as u64) << 48, 0],
Self::InvalidateAll => [0x30, 0],
# cmd-asid-field
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -135,7 +135,7 @@
// `CMD_CFGI_STE_RANGE` with Range [68:64] of 31.
Self::ForgetAll => [0x04, 31],
// ASID [63:48], VMID [47:32].
- Self::InvalidateAsid(asid) => [0x11 | (asid.get() as u64) << 48, 0],
+ Self::InvalidateAsid(asid) => [0x11 | (asid.get() as u64) << 32, 0],
Self::InvalidateAll => [0x30, 0],
// CS [13:12].
Self::Sync(signal) => {
# cmd-invalidate-all-opcode
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -136,7 +136,7 @@
Self::ForgetAll => [0x04, 31],
// ASID [63:48], VMID [47:32].
Self::InvalidateAsid(asid) => [0x11 | (asid.get() as u64) << 48, 0],
- Self::InvalidateAll => [0x30, 0],
+ Self::InvalidateAll => [0x10, 0],
// CS [13:12].
Self::Sync(signal) => {
let cs = match signal {
# event-rnw-bit
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -238,7 +238,7 @@
};
let attempt = match code {
Code::Translation | Code::AddressSize | Code::AccessFlag | Code::Permission => {
- Some(Attempt { address: record[2], write: record[1] & 1 << 35 == 0 })
+ Some(Attempt { address: record[2], write: record[1] & 1 << 34 == 0 })
}
_ => None,
};
# event-rnw-polarity
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -238,7 +238,7 @@
};
let attempt = match code {
Code::Translation | Code::AddressSize | Code::AccessFlag | Code::Permission => {
- Some(Attempt { address: record[2], write: record[1] & 1 << 35 == 0 })
+ Some(Attempt { address: record[2], write: record[1] & 1 << 35 != 0 })
}
_ => None,
};
# event-address-word
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -238,7 +238,7 @@
};
let attempt = match code {
Code::Translation | Code::AddressSize | Code::AccessFlag | Code::Permission => {
- Some(Attempt { address: record[2], write: record[1] & 1 << 35 == 0 })
+ Some(Attempt { address: record[3], write: record[1] & 1 << 35 == 0 })
}
_ => None,
};
# event-stream-field
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -242,5 +242,5 @@
}
_ => None,
};
- Event { stream: (record[0] >> 32) as u32, code, attempt }
+ Event { stream: (record[0] >> 12) as u32, code, attempt }
}
# event-permission-unnamed
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -229,7 +229,6 @@
0x10 => Code::Translation,
0x11 => Code::AddressSize,
0x12 => Code::AccessFlag,
- 0x13 => Code::Permission,
0x20 => Code::TlbConflict,
0x21 => Code::ConfigurationConflict,
0x24 => Code::PageRequest,
# event-attempt-on-any
--- a/toyos-smmu/src/queue.rs
+++ b/toyos-smmu/src/queue.rs
@@ -240,7 +240,7 @@
Code::Translation | Code::AddressSize | Code::AccessFlag | Code::Permission => {
Some(Attempt { address: record[2], write: record[1] & 1 << 35 == 0 })
}
- _ => None,
+ _ => Some(Attempt { address: record[2], write: true }),
};
Event { stream: (record[0] >> 32) as u32, code, attempt }
}
# probe-no-stage1
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -147,7 +147,7 @@
if idr0 & 1 << 4 == 0 && !coherent_override {
return Err(Lacks::CoherentAccess);
}
- if idr0 & 1 << 1 == 0 {
+ if false {
return Err(Lacks::Stage1);
}
if idr0 & 1 << 3 == 0 {
# probe-ttf-bit
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -150,7 +150,7 @@
if idr0 & 1 << 1 == 0 {
return Err(Lacks::Stage1);
}
- if idr0 & 1 << 3 == 0 {
+ if idr0 & 1 << 2 == 0 {
return Err(Lacks::Aarch64Tables);
}
// `TTENDIAN` [22:21]: `0b00` mixed and `0b10` little-endian can be set to little-endian.
# probe-big-endian
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -154,7 +154,7 @@
return Err(Lacks::Aarch64Tables);
}
// `TTENDIAN` [22:21]: `0b00` mixed and `0b10` little-endian can be set to little-endian.
- if idr0 >> 21 & 0b11 == 0b11 {
+ if false {
return Err(Lacks::LittleEndianTables);
}
// `STALL_MODEL` [25:24]: `0b00` stall and terminate, `0b01` terminate only.
# probe-forced-stall
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -160,7 +160,7 @@
// `STALL_MODEL` [25:24]: `0b00` stall and terminate, `0b01` terminate only.
let stall = match idr0 >> 24 & 0b11 {
0b00 => true,
- 0b01 => false,
+ 0b01 | 0b10 => false,
other => return Err(Lacks::Termination(other as u8)),
};
if idr5 & 1 << 4 == 0 {
# probe-no-4k
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -163,7 +163,7 @@
0b01 => false,
other => return Err(Lacks::Termination(other as u8)),
};
- if idr5 & 1 << 4 == 0 {
+ if false {
return Err(Lacks::Granule4K);
}
if idr1 & (1 << 30 | 1 << 29) != 0 {
# probe-preset
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -166,7 +166,7 @@
if idr5 & 1 << 4 == 0 {
return Err(Lacks::Granule4K);
}
- if idr1 & (1 << 30 | 1 << 29) != 0 {
+ if idr1 & (1 << 30) != 0 {
return Err(Lacks::FixedStructures);
}
let stream_bits = (idr1 & 0x3F) as u8;
# probe-stream-bits-bound
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -172,7 +172,7 @@
let stream_bits = (idr1 & 0x3F) as u8;
let command_queue_log2 = (idr1 >> 21 & 0x1F) as u8;
let event_queue_log2 = (idr1 >> 16 & 0x1F) as u8;
- if stream_bits > 32 {
+ if stream_bits > 63 {
return Err(Lacks::Size(stream_bits));
}
if command_queue_log2 > 19 {
# probe-queue-bound
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -175,7 +175,7 @@
if stream_bits > 32 {
return Err(Lacks::Size(stream_bits));
}
- if command_queue_log2 > 19 {
+ if command_queue_log2 > 31 {
return Err(Lacks::Size(command_queue_log2));
}
if event_queue_log2 > 19 {
# probe-eventq-field
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -171,7 +171,7 @@
}
let stream_bits = (idr1 & 0x3F) as u8;
let command_queue_log2 = (idr1 >> 21 & 0x1F) as u8;
- let event_queue_log2 = (idr1 >> 16 & 0x1F) as u8;
+ let event_queue_log2 = (idr1 >> 21 & 0x1F) as u8;
if stream_bits > 32 {
return Err(Lacks::Size(stream_bits));
}
# probe-cohacc-bit
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -144,7 +144,7 @@
/// with the IORT's `COHACC override` (DEN 0049 Table 14), which stands for
/// `IDR0.COHACC` [4] where it is set.
pub const fn probe(idr0: u32, idr1: u32, idr5: u32, coherent_override: bool) -> Result<Unit, Lacks> {
- if idr0 & 1 << 4 == 0 && !coherent_override {
+ if idr0 & 1 << 5 == 0 && !coherent_override {
return Err(Lacks::CoherentAccess);
}
if idr0 & 1 << 1 == 0 {
# probe-incoherent-accepted
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -144,7 +144,7 @@
/// with the IORT's `COHACC override` (DEN 0049 Table 14), which stands for
/// `IDR0.COHACC` [4] where it is set.
pub const fn probe(idr0: u32, idr1: u32, idr5: u32, coherent_override: bool) -> Result<Unit, Lacks> {
- if idr0 & 1 << 4 == 0 && !coherent_override {
+ if false {
return Err(Lacks::CoherentAccess);
}
if idr0 & 1 << 1 == 0 {
# probe-override-ignored
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -144,7 +144,7 @@
/// with the IORT's `COHACC override` (DEN 0049 Table 14), which stands for
/// `IDR0.COHACC` [4] where it is set.
pub const fn probe(idr0: u32, idr1: u32, idr5: u32, coherent_override: bool) -> Result<Unit, Lacks> {
- if idr0 & 1 << 4 == 0 && !coherent_override {
+ if idr0 & 1 << 4 == 0 {
return Err(Lacks::CoherentAccess);
}
if idr0 & 1 << 1 == 0 {
# probe-oas-table
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -185,7 +185,7 @@
stream_bits,
command_queue_log2,
event_queue_log2,
- output_bits: [32, 36, 40, 42, 44, 48, 52, 56][(idr5 & 0b111) as usize],
+ output_bits: [32, 36, 40, 44, 42, 48, 52, 56][(idr5 & 0b111) as usize],
asid16: idr0 & 1 << 12 != 0,
stall,
})
# asid-wider-than-unit
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -195,7 +195,7 @@
/// `tag` as an ASID of this unit: eight bits where `IDR0.ASID16` is
/// clear, under which a wider one makes its context descriptor ILLEGAL.
pub const fn asid(&self, tag: u16) -> Option<Asid> {
- if self.asid16 || tag <= 0xFF {
+ if true {
Some(Asid(tag))
} else {
None
# output-unbounded
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -224,7 +224,7 @@
/// Whether the unit reads all of `bytes` at `address`: none of them at
/// or past `1 << IDR5.OAS`.
pub(crate) const fn reaches(&self, address: u64, bytes: u64) -> bool {
- address + bytes <= 1 << self.output_bits
+ address + bytes <= 1 << 56
}
/// `bytes` at `address`, aligned to their own size, where the unit reads
# output-end-exclusive
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -224,7 +224,7 @@
/// Whether the unit reads all of `bytes` at `address`: none of them at
/// or past `1 << IDR5.OAS`.
pub(crate) const fn reaches(&self, address: u64, bytes: u64) -> bool {
- address + bytes <= 1 << self.output_bits
+ address + bytes < 1 << self.output_bits
}
/// `bytes` at `address`, aligned to their own size, where the unit reads
# output-base-alone
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -224,7 +224,7 @@
/// Whether the unit reads all of `bytes` at `address`: none of them at
/// or past `1 << IDR5.OAS`.
pub(crate) const fn reaches(&self, address: u64, bytes: u64) -> bool {
- address + bytes <= 1 << self.output_bits
+ address < 1 << self.output_bits
}
/// `bytes` at `address`, aligned to their own size, where the unit reads
# strtab-misaligned
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -240,7 +240,7 @@
/// its own size as the unit reads its address, or it ends past the
/// unit's output size.
pub const fn stream_table(&self, table: Phys<6>, log2size: u8) -> Option<(u64, u32)> {
- if log2size > self.stream_bits || !self.holds(table.get(), 64 << log2size) {
+ if log2size > self.stream_bits || !self.reaches(table.get(), 64 << log2size) {
return None;
}
Some((1 << 62 | table.get(), log2size as u32))
# strtab-past-streams
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -240,7 +240,7 @@
/// its own size as the unit reads its address, or it ends past the
/// unit's output size.
pub const fn stream_table(&self, table: Phys<6>, log2size: u8) -> Option<(u64, u32)> {
- if log2size > self.stream_bits || !self.holds(table.get(), 64 << log2size) {
+ if !self.holds(table.get(), 64 << log2size) {
return None;
}
Some((1 << 62 | table.get(), log2size as u32))
# strtab-past-output
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -240,7 +240,7 @@
/// its own size as the unit reads its address, or it ends past the
/// unit's output size.
pub const fn stream_table(&self, table: Phys<6>, log2size: u8) -> Option<(u64, u32)> {
- if log2size > self.stream_bits || !self.holds(table.get(), 64 << log2size) {
+ if log2size > self.stream_bits || table.get() & ((64 << log2size) - 1) != 0 {
return None;
}
Some((1 << 62 | table.get(), log2size as u32))
# strtab-no-read-allocate
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -243,7 +243,7 @@
if log2size > self.stream_bits || !self.holds(table.get(), 64 << log2size) {
return None;
}
- Some((1 << 62 | table.get(), log2size as u32))
+ Some((table.get(), log2size as u32))
}
/// `SMMU_CMDQ_BASE` (§6.3.26) for a queue of `1 << log2size` 16-byte
# cmdq-past-unit
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -252,7 +252,7 @@
/// or where the queue is not aligned to the larger of its size and 32
/// bytes.
pub const fn command_queue(&self, queue: Phys<5>, log2size: u8) -> Option<(u64, Commands)> {
- if log2size > self.command_queue_log2 || !self.holds(queue.get(), 16 << log2size) {
+ if !self.holds(queue.get(), 16 << log2size) {
return None;
}
Some((1 << 62 | queue.get() | log2size as u64, Commands(Indexes { log2size })))
# cmdq-misaligned
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -252,7 +252,7 @@
/// or where the queue is not aligned to the larger of its size and 32
/// bytes.
pub const fn command_queue(&self, queue: Phys<5>, log2size: u8) -> Option<(u64, Commands)> {
- if log2size > self.command_queue_log2 || !self.holds(queue.get(), 16 << log2size) {
+ if log2size > self.command_queue_log2 || !self.reaches(queue.get(), 16 << log2size) {
return None;
}
Some((1 << 62 | queue.get() | log2size as u64, Commands(Indexes { log2size })))
# cmdq-past-output
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -252,7 +252,7 @@
/// or where the queue is not aligned to the larger of its size and 32
/// bytes.
pub const fn command_queue(&self, queue: Phys<5>, log2size: u8) -> Option<(u64, Commands)> {
- if log2size > self.command_queue_log2 || !self.holds(queue.get(), 16 << log2size) {
+ if log2size > self.command_queue_log2 || queue.get() & ((16 << log2size) - 1) != 0 {
return None;
}
Some((1 << 62 | queue.get() | log2size as u64, Commands(Indexes { log2size })))
# eventq-entry-size
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -261,7 +261,7 @@
/// `SMMU_EVENTQ_BASE` (§6.3.29) for a queue of `1 << log2size` 32-byte
/// records, and its indexes: `WA` [62], the address, `LOG2SIZE` [4:0].
pub const fn event_queue(&self, queue: Phys<5>, log2size: u8) -> Option<(u64, Events)> {
- if log2size > self.event_queue_log2 || !self.holds(queue.get(), 32 << log2size) {
+ if log2size > self.event_queue_log2 || !self.holds(queue.get(), 16 << log2size) {
return None;
}
Some((1 << 62 | queue.get() | log2size as u64, Events(Indexes { log2size })))
# eventq-past-unit
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -261,7 +261,7 @@
/// `SMMU_EVENTQ_BASE` (§6.3.29) for a queue of `1 << log2size` 32-byte
/// records, and its indexes: `WA` [62], the address, `LOG2SIZE` [4:0].
pub const fn event_queue(&self, queue: Phys<5>, log2size: u8) -> Option<(u64, Events)> {
- if log2size > self.event_queue_log2 || !self.holds(queue.get(), 32 << log2size) {
+ if !self.holds(queue.get(), 32 << log2size) {
return None;
}
Some((1 << 62 | queue.get() | log2size as u64, Events(Indexes { log2size })))
# eventq-past-output
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -261,7 +261,7 @@
/// `SMMU_EVENTQ_BASE` (§6.3.29) for a queue of `1 << log2size` 32-byte
/// records, and its indexes: `WA` [62], the address, `LOG2SIZE` [4:0].
pub const fn event_queue(&self, queue: Phys<5>, log2size: u8) -> Option<(u64, Events)> {
- if log2size > self.event_queue_log2 || !self.holds(queue.get(), 32 << log2size) {
+ if log2size > self.event_queue_log2 || queue.get() & ((32 << log2size) - 1) != 0 {
return None;
}
Some((1 << 62 | queue.get() | log2size as u64, Events(Indexes { log2size })))
# errors-not-toggled
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -62,7 +62,7 @@
/// `SMMU_GERROR` (§6.3.19): an error is active while its bit differs from
/// `SMMU_GERRORN`'s, and writing `GERRORN` equal acknowledges it (§7.5).
pub const fn active_errors(gerror: u32, gerrorn: u32) -> u32 {
- gerror ^ gerrorn
+ gerror & !gerrorn
}
/// `SMMU_GERROR.CMDQ_ERR`: the command queue stopped on [`CommandError`].
# cmd-error-field
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -88,7 +88,7 @@
}
pub const fn command_error(cons: u32) -> CommandError {
- match (cons >> 24 & 0x7F) as u8 {
+ match (cons >> 24) as u8 {
0 => CommandError::None,
1 => CommandError::Illegal,
2 => CommandError::Abort,
# cr1-table-shareability
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -41,7 +41,7 @@
/// inner-shareable write-back memory — `TABLE_SH` [11:10], `TABLE_OC` [9:8],
/// `TABLE_IC` [7:6], `QUEUE_SH` [5:4], `QUEUE_OC` [3:2], `QUEUE_IC` [1:0],
/// each shareability `0b11` and each cacheability `0b01`.
-pub const CR1_WRITE_BACK: u32 = 0b11 << 10 | 0b01 << 8 | 0b01 << 6 | 0b11 << 4 | 0b01 << 2 | 0b01;
+pub const CR1_WRITE_BACK: u32 = 0b11 << 12 | 0b01 << 8 | 0b01 << 6 | 0b11 << 4 | 0b01 << 2 | 0b01;
/// `SMMU_CR2` (§6.3.12): `RECINVSID` [1], so a transaction under a StreamID
/// past the stream table is recorded as well as aborted, and `PTM` [2], so
# cr2-broadcast
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -47,7 +47,7 @@
/// past the stream table is recorded as well as aborted, and `PTM` [2], so
/// no CPU's broadcast TLB invalidation reaches the unit's entries: its ASIDs
/// are its own. `E2H` [0] stays clear.
-pub const CR2_RECORD_PRIVATE: u32 = 1 << 1 | 1 << 2;
+pub const CR2_RECORD_PRIVATE: u32 = 1 << 1;
/// `SMMU_GBPA` (§6.3.15): what happens to every transaction while `SMMUEN`
/// is clear. `ABORT` [20] aborts them; a write takes effect by carrying
# gbpa-abort-bit
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -52,7 +52,7 @@
/// `SMMU_GBPA` (§6.3.15): what happens to every transaction while `SMMUEN`
/// is clear. `ABORT` [20] aborts them; a write takes effect by carrying
/// `Update` [31], which reads back set until the unit has taken it (§6.3.15.1).
-pub const GBPA_ABORT: u32 = 1 << 20;
+pub const GBPA_ABORT: u32 = 1 << 19;
pub const GBPA_UPDATE: u32 = 1 << 31;
/// `SMMU_IRQ_CTRL` (§6.3.17), and `SMMU_IRQ_CTRLACK` as `SMMU_CR0ACK`.
# smmu-offset-gerrorn
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -19,7 +19,7 @@
pub const IRQ_CTRL: usize = 0x050;
pub const IRQ_CTRLACK: usize = 0x054;
pub const GERROR: usize = 0x060;
-pub const GERRORN: usize = 0x064;
+pub const GERRORN: usize = 0x068;
pub const STRTAB_BASE: usize = 0x080;
pub const STRTAB_BASE_CFG: usize = 0x088;
pub const CMDQ_BASE: usize = 0x090;
# smmu-offset-strtab-cfg
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -21,7 +21,7 @@
pub const GERROR: usize = 0x060;
pub const GERRORN: usize = 0x064;
pub const STRTAB_BASE: usize = 0x080;
-pub const STRTAB_BASE_CFG: usize = 0x088;
+pub const STRTAB_BASE_CFG: usize = 0x084;
pub const CMDQ_BASE: usize = 0x090;
pub const CMDQ_PROD: usize = 0x098;
pub const CMDQ_CONS: usize = 0x09C;
# smmu-eventq-cons-in-page-0
--- a/toyos-smmu/src/unit.rs
+++ b/toyos-smmu/src/unit.rs
@@ -29,7 +29,7 @@
/// The event queue's indexes are in register page 1, 64 KiB above page 0
/// (§6.1, §6.2.2): `SMMU_EVENTQ_PROD` and `SMMU_EVENTQ_CONS` at 0xA8 and 0xAC of it.
pub const EVENTQ_PROD: usize = 0x1_00A8;
-pub const EVENTQ_CONS: usize = 0x1_00AC;
+pub const EVENTQ_CONS: usize = 0x00AC;
/// `SMMU_CR0` (§6.3.9), and `SMMU_CR0ACK`, which reads each bit back once
/// the unit has acted on it.
# phys-past-48
--- a/toyos-phys/src/lib.rs
+++ b/toyos-phys/src/lib.rs
@@ -11,7 +11,7 @@
pub struct Phys<const ALIGN: u32>(u64);
impl<const ALIGN: u32> Phys<ALIGN> {
- const FIELD: u64 = (1 << 48) - (1 << ALIGN);
+ const FIELD: u64 = 0u64.wrapping_sub(1 << ALIGN);
pub const fn new(address: u64) -> Option<Self> {
if address & !Self::FIELD == 0 {
# phys-unaligned
--- a/toyos-phys/src/lib.rs
+++ b/toyos-phys/src/lib.rs
@@ -11,7 +11,7 @@
pub struct Phys<const ALIGN: u32>(u64);
impl<const ALIGN: u32> Phys<ALIGN> {
- const FIELD: u64 = (1 << 48) - (1 << ALIGN);
+ const FIELD: u64 = (1 << 48) - 1;
pub const fn new(address: u64) -> Option<Self> {
if address & !Self::FIELD == 0 {
# phys-of-keeps-the-word
--- a/toyos-phys/src/lib.rs
+++ b/toyos-phys/src/lib.rs
@@ -24,7 +24,7 @@
/// The address a word holds in its bits `[47:ALIGN]`, whatever its other
/// bits are.
pub const fn of(word: u64) -> Self {
- Self(word & Self::FIELD)
+ Self(word)
}
pub const fn get(self) -> u64 { |
|
Mutations at f8022b7, round 2, of The patches# its-mapd-size
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -41,7 +41,7 @@
match self {
// Size [4:0] of doubleword 1 is the EventID bits minus one; ITT_addr [51:8] of doubleword 2.
Self::MapDevice { device: id, table, events } => {
- [device(0x08, id), (events.0 - 1) as u64, V | table.get(), 0]
+ [device(0x08, id), events.0 as u64, V | table.get(), 0]
}
Self::UnmapDevice { device: id } => [device(0x08, id), 0, 0, 0],
// RDbase [51:16] and ICID [15:0] of doubleword 2.
# its-mapd-not-valid
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -41,7 +41,7 @@
match self {
// Size [4:0] of doubleword 1 is the EventID bits minus one; ITT_addr [51:8] of doubleword 2.
Self::MapDevice { device: id, table, events } => {
- [device(0x08, id), (events.0 - 1) as u64, V | table.get(), 0]
+ [device(0x08, id), (events.0 - 1) as u64, table.get(), 0]
}
Self::UnmapDevice { device: id } => [device(0x08, id), 0, 0, 0],
// RDbase [51:16] and ICID [15:0] of doubleword 2.
# its-unmapd-valid
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -43,7 +43,7 @@
Self::MapDevice { device: id, table, events } => {
[device(0x08, id), (events.0 - 1) as u64, V | table.get(), 0]
}
- Self::UnmapDevice { device: id } => [device(0x08, id), 0, 0, 0],
+ Self::UnmapDevice { device: id } => [device(0x08, id), 0, V, 0],
// RDbase [51:16] and ICID [15:0] of doubleword 2.
Self::MapCollection { collection, target } => [0x09, 0, V | target.0 << 16 | collection.0 as u64, 0],
// pINTID [63:32] of doubleword 1; ICID [15:0] of doubleword 2.
# its-mapc-rdbase-field
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -45,7 +45,7 @@
}
Self::UnmapDevice { device: id } => [device(0x08, id), 0, 0, 0],
// RDbase [51:16] and ICID [15:0] of doubleword 2.
- Self::MapCollection { collection, target } => [0x09, 0, V | target.0 << 16 | collection.0 as u64, 0],
+ Self::MapCollection { collection, target } => [0x09, 0, V | target.0 << 32 | collection.0 as u64, 0],
// pINTID [63:32] of doubleword 1; ICID [15:0] of doubleword 2.
Self::MapEvent { device: id, event, lpi, collection } => {
[device(0x0A, id), (lpi.intid() as u64) << 32 | event.0 as u64, collection.0 as u64, 0]
# its-mapc-not-valid
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -45,7 +45,7 @@
}
Self::UnmapDevice { device: id } => [device(0x08, id), 0, 0, 0],
// RDbase [51:16] and ICID [15:0] of doubleword 2.
- Self::MapCollection { collection, target } => [0x09, 0, V | target.0 << 16 | collection.0 as u64, 0],
+ Self::MapCollection { collection, target } => [0x09, 0, target.0 << 16 | collection.0 as u64, 0],
// pINTID [63:32] of doubleword 1; ICID [15:0] of doubleword 2.
Self::MapEvent { device: id, event, lpi, collection } => {
[device(0x0A, id), (lpi.intid() as u64) << 32 | event.0 as u64, collection.0 as u64, 0]
# its-mapti-fields-swapped
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -48,7 +48,7 @@
Self::MapCollection { collection, target } => [0x09, 0, V | target.0 << 16 | collection.0 as u64, 0],
// pINTID [63:32] of doubleword 1; ICID [15:0] of doubleword 2.
Self::MapEvent { device: id, event, lpi, collection } => {
- [device(0x0A, id), (lpi.intid() as u64) << 32 | event.0 as u64, collection.0 as u64, 0]
+ [device(0x0A, id), (event.0 as u64) << 32 | lpi.intid() as u64, collection.0 as u64, 0]
}
Self::Reconfigure { device: id, event } => [device(0x0C, id), event.0 as u64, 0, 0],
Self::Discard { device: id, event } => [device(0x0F, id), event.0 as u64, 0, 0],
# its-mapti-collection-word
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -48,7 +48,7 @@
Self::MapCollection { collection, target } => [0x09, 0, V | target.0 << 16 | collection.0 as u64, 0],
// pINTID [63:32] of doubleword 1; ICID [15:0] of doubleword 2.
Self::MapEvent { device: id, event, lpi, collection } => {
- [device(0x0A, id), (lpi.intid() as u64) << 32 | event.0 as u64, collection.0 as u64, 0]
+ [device(0x0A, id), (lpi.intid() as u64) << 32 | event.0 as u64, 0, collection.0 as u64]
}
Self::Reconfigure { device: id, event } => [device(0x0C, id), event.0 as u64, 0, 0],
Self::Discard { device: id, event } => [device(0x0F, id), event.0 as u64, 0, 0],
# its-device-field
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -36,7 +36,7 @@
pub const fn words(self) -> [u64; 4] {
// DeviceID is bits [63:32] of doubleword 0, and EventID bits [31:0] of doubleword 1.
const fn device(number: u64, device: u32) -> u64 {
- number | (device as u64) << 32
+ number | (device as u64) << 8
}
match self {
// Size [4:0] of doubleword 1 is the EventID bits minus one; ITT_addr [51:8] of doubleword 2.
# its-sync-rdbase-field
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -52,7 +52,7 @@
}
Self::Reconfigure { device: id, event } => [device(0x0C, id), event.0 as u64, 0, 0],
Self::Discard { device: id, event } => [device(0x0F, id), event.0 as u64, 0, 0],
- Self::Sync(target) => [0x05, 0, target.0 << 16, 0],
+ Self::Sync(target) => [0x05, 0, target.0, 0],
}
}
}
# its-inv-is-discard
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -50,7 +50,7 @@
Self::MapEvent { device: id, event, lpi, collection } => {
[device(0x0A, id), (lpi.intid() as u64) << 32 | event.0 as u64, collection.0 as u64, 0]
}
- Self::Reconfigure { device: id, event } => [device(0x0C, id), event.0 as u64, 0, 0],
+ Self::Reconfigure { device: id, event } => [device(0x0F, id), event.0 as u64, 0, 0],
Self::Discard { device: id, event } => [device(0x0F, id), event.0 as u64, 0, 0],
Self::Sync(target) => [0x05, 0, target.0 << 16, 0],
}
# its-discard-is-inv
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -51,7 +51,7 @@
[device(0x0A, id), (lpi.intid() as u64) << 32 | event.0 as u64, collection.0 as u64, 0]
}
Self::Reconfigure { device: id, event } => [device(0x0C, id), event.0 as u64, 0, 0],
- Self::Discard { device: id, event } => [device(0x0F, id), event.0 as u64, 0, 0],
+ Self::Discard { device: id, event } => [device(0x0C, id), event.0 as u64, 0, 0],
Self::Sync(target) => [0x05, 0, target.0 << 16, 0],
}
}
# its-inv-event-high-half
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -50,7 +50,7 @@
Self::MapEvent { device: id, event, lpi, collection } => {
[device(0x0A, id), (lpi.intid() as u64) << 32 | event.0 as u64, collection.0 as u64, 0]
}
- Self::Reconfigure { device: id, event } => [device(0x0C, id), event.0 as u64, 0, 0],
+ Self::Reconfigure { device: id, event } => [device(0x0C, id), (event.0 as u64) << 32, 0, 0],
Self::Discard { device: id, event } => [device(0x0F, id), event.0 as u64, 0, 0],
Self::Sync(target) => [0x05, 0, target.0 << 16, 0],
}
# its-discard-event-word
--- a/toyos-its/src/command.rs
+++ b/toyos-its/src/command.rs
@@ -51,7 +51,7 @@
[device(0x0A, id), (lpi.intid() as u64) << 32 | event.0 as u64, collection.0 as u64, 0]
}
Self::Reconfigure { device: id, event } => [device(0x0C, id), event.0 as u64, 0, 0],
- Self::Discard { device: id, event } => [device(0x0F, id), event.0 as u64, 0, 0],
+ Self::Discard { device: id, event } => [device(0x0F, id), 0, event.0 as u64, 0],
Self::Sync(target) => [0x05, 0, target.0 << 16, 0],
}
}
# its-target-form-swapped
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -172,7 +172,7 @@
/// The redistributor at `frame` whose `GICR_TYPER.Processor_Number` is
/// `number`, as this ITS names it.
pub const fn target(&self, number: u16, frame: Phys<16>) -> Target {
- Target(if self.physical_targets { frame.get() >> 16 } else { number as u64 })
+ Target(if !self.physical_targets { frame.get() >> 16 } else { number as u64 })
}
}
# its-events-unbounded
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -145,7 +145,7 @@
/// A translation table of `1 << bits` events. `None` for no bit, or more
/// than the ITS's EventIDs have.
pub const fn events(&self, bits: u8) -> Option<EventBits> {
- if bits >= 1 && bits <= self.event_bits {
+ if bits >= 1 {
Some(EventBits(bits))
} else {
None
# its-events-zero
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -145,7 +145,7 @@
/// A translation table of `1 << bits` events. `None` for no bit, or more
/// than the ITS's EventIDs have.
pub const fn events(&self, bits: u8) -> Option<EventBits> {
- if bits >= 1 && bits <= self.event_bits {
+ if bits <= self.event_bits {
Some(EventBits(bits))
} else {
None
# its-event-unbounded
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -110,7 +110,7 @@
impl EventBits {
/// `id` as an event of a device whose table holds this many.
pub const fn event(self, id: u32) -> Option<Event> {
- if (id as u64) >> self.0 == 0 {
+ if true {
Some(Event(id))
} else {
None
# its-event-one-bit-wide
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -110,7 +110,7 @@
impl EventBits {
/// `id` as an event of a device whose table holds this many.
pub const fn event(self, id: u32) -> Option<Event> {
- if (id as u64) >> self.0 == 0 {
+ if (id as u64) >> (self.0 + 1) == 0 {
Some(Event(id))
} else {
None
# its-itt-bytes
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -155,7 +155,7 @@
/// The zeroed bytes `MAPD` is given for that table, at a 256-byte
/// aligned address.
pub const fn itt_bytes(&self, events: EventBits) -> u64 {
- (self.itt_entry_bytes as u64) << events.0
+ (self.itt_entry_bytes as u64) << (events.0 - 1)
}
/// The collections this ITS has once its collection table holds
# its-no-physical-lpis
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -83,7 +83,7 @@
}
pub const fn probe(typer: u64) -> Result<Its, Lacks> {
- if typer & 1 == 0 {
+ if false {
return Err(Lacks::PhysicalLpis);
}
Ok(Its {
# its-typer-minus-one
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -88,7 +88,7 @@
}
Ok(Its {
device_bits: (typer >> 13 & 0x1F) as u8 + 1,
- event_bits: (typer >> 8 & 0x1F) as u8 + 1,
+ event_bits: (typer >> 8 & 0x1F) as u8,
itt_entry_bytes: (typer >> 4 & 0xF) as u8 + 1,
held: (typer >> 24) as u8,
cumulative: typer & 1 << 2 != 0,
# its-typer-devbits-field
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -87,7 +87,7 @@
return Err(Lacks::PhysicalLpis);
}
Ok(Its {
- device_bits: (typer >> 13 & 0x1F) as u8 + 1,
+ device_bits: (typer >> 12 & 0x1F) as u8 + 1,
event_bits: (typer >> 8 & 0x1F) as u8 + 1,
itt_entry_bytes: (typer >> 4 & 0xF) as u8 + 1,
held: (typer >> 24) as u8,
# its-typer-itt-entry-field
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -89,7 +89,7 @@
Ok(Its {
device_bits: (typer >> 13 & 0x1F) as u8 + 1,
event_bits: (typer >> 8 & 0x1F) as u8 + 1,
- itt_entry_bytes: (typer >> 4 & 0xF) as u8 + 1,
+ itt_entry_bytes: (typer >> 4 & 0xF) as u8,
held: (typer >> 24) as u8,
cumulative: typer & 1 << 2 != 0,
collection_bits: if typer & 1 << 36 == 0 { 16 } else { (typer >> 32 & 0xF) as u8 + 1 },
# its-typer-pta-bit
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -93,7 +93,7 @@
held: (typer >> 24) as u8,
cumulative: typer & 1 << 2 != 0,
collection_bits: if typer & 1 << 36 == 0 { 16 } else { (typer >> 32 & 0xF) as u8 + 1 },
- physical_targets: typer & 1 << 19 != 0,
+ physical_targets: typer & 1 << 18 != 0,
})
}
# its-typer-hcc-field
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -90,7 +90,7 @@
device_bits: (typer >> 13 & 0x1F) as u8 + 1,
event_bits: (typer >> 8 & 0x1F) as u8 + 1,
itt_entry_bytes: (typer >> 4 & 0xF) as u8 + 1,
- held: (typer >> 24) as u8,
+ held: (typer >> 16) as u8,
cumulative: typer & 1 << 2 != 0,
collection_bits: if typer & 1 << 36 == 0 { 16 } else { (typer >> 32 & 0xF) as u8 + 1 },
physical_targets: typer & 1 << 19 != 0,
# its-typer-cct-bit
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -91,7 +91,7 @@
event_bits: (typer >> 8 & 0x1F) as u8 + 1,
itt_entry_bytes: (typer >> 4 & 0xF) as u8 + 1,
held: (typer >> 24) as u8,
- cumulative: typer & 1 << 2 != 0,
+ cumulative: typer & 1 << 3 != 0,
collection_bits: if typer & 1 << 36 == 0 { 16 } else { (typer >> 32 & 0xF) as u8 + 1 },
physical_targets: typer & 1 << 19 != 0,
})
# its-typer-cil-bit
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -92,7 +92,7 @@
itt_entry_bytes: (typer >> 4 & 0xF) as u8 + 1,
held: (typer >> 24) as u8,
cumulative: typer & 1 << 2 != 0,
- collection_bits: if typer & 1 << 36 == 0 { 16 } else { (typer >> 32 & 0xF) as u8 + 1 },
+ collection_bits: if typer & 1 << 37 == 0 { 16 } else { (typer >> 32 & 0xF) as u8 + 1 },
physical_targets: typer & 1 << 19 != 0,
})
}
# its-typer-cidbits-minus-one
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -92,7 +92,7 @@
itt_entry_bytes: (typer >> 4 & 0xF) as u8 + 1,
held: (typer >> 24) as u8,
cumulative: typer & 1 << 2 != 0,
- collection_bits: if typer & 1 << 36 == 0 { 16 } else { (typer >> 32 & 0xF) as u8 + 1 },
+ collection_bits: if typer & 1 << 36 == 0 { 16 } else { (typer >> 32 & 0xF) as u8 },
physical_targets: typer & 1 << 19 != 0,
})
}
# its-collection-unbounded
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -128,7 +128,7 @@
impl Collections {
pub const fn collection(self, id: u16) -> Option<Collection> {
- if (id as u32) < self.0 {
+ if true {
Some(Collection(id))
} else {
None
# its-collection-inclusive
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -128,7 +128,7 @@
impl Collections {
pub const fn collection(self, id: u16) -> Option<Collection> {
- if (id as u32) < self.0 {
+ if (id as u32) <= self.0 {
Some(Collection(id))
} else {
None
# its-collections-always-held
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -163,7 +163,7 @@
/// §5.3.1): the table's, those the ITS holds itself where it has no
/// table or counts them beside it, and no more than an ICID numbers.
pub const fn collections(&self, in_table: u64) -> Collections {
- let held = if in_table == 0 || self.cumulative { self.held as u64 } else { 0 };
+ let held = self.held as u64;
let numbered = 1u64 << self.collection_bits;
let total = held.saturating_add(in_table);
Collections(if total < numbered { total } else { numbered } as u32)
# its-collections-held-without-a-table-alone
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -163,7 +163,7 @@
/// §5.3.1): the table's, those the ITS holds itself where it has no
/// table or counts them beside it, and no more than an ICID numbers.
pub const fn collections(&self, in_table: u64) -> Collections {
- let held = if in_table == 0 || self.cumulative { self.held as u64 } else { 0 };
+ let held = if in_table == 0 { self.held as u64 } else { 0 };
let numbered = 1u64 << self.collection_bits;
let total = held.saturating_add(in_table);
Collections(if total < numbered { total } else { numbered } as u32)
# its-collections-held-under-cct-alone
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -163,7 +163,7 @@
/// §5.3.1): the table's, those the ITS holds itself where it has no
/// table or counts them beside it, and no more than an ICID numbers.
pub const fn collections(&self, in_table: u64) -> Collections {
- let held = if in_table == 0 || self.cumulative { self.held as u64 } else { 0 };
+ let held = if self.cumulative { self.held as u64 } else { 0 };
let numbered = 1u64 << self.collection_bits;
let total = held.saturating_add(in_table);
Collections(if total < numbered { total } else { numbered } as u32)
# its-collections-past-the-icid
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -166,7 +166,7 @@
let held = if in_table == 0 || self.cumulative { self.held as u64 } else { 0 };
let numbered = 1u64 << self.collection_bits;
let total = held.saturating_add(in_table);
- Collections(if total < numbered { total } else { numbered } as u32)
+ Collections(if total < u32::MAX as u64 { total } else { u32::MAX as u64 } as u32)
}
/// The redistributor at `frame` whose `GICR_TYPER.Processor_Number` is
# its-table-type-field
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -219,7 +219,7 @@
}
pub const fn table(baser: u64) -> Backing {
- let table = match baser >> 56 & 0b111 {
+ let table = match baser >> 59 & 0b111 {
0b000 => Table::Unimplemented,
0b001 => Table::Devices,
0b100 => Table::Collections,
# its-table-collections
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -222,7 +222,7 @@
let table = match baser >> 56 & 0b111 {
0b000 => Table::Unimplemented,
0b001 => Table::Devices,
- 0b100 => Table::Collections,
+ 0b010 => Table::Collections,
other => Table::Other(other as u8),
};
let page = match baser >> 8 & 0b11 {
# its-table-entry-size
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -231,7 +231,7 @@
// `0b11` is reserved and treated as `0b10`.
_ => PageSize::K64,
};
- Backing { table, page, entry_bytes: (baser >> 48 & 0x1F) as u8 + 1 }
+ Backing { table, page, entry_bytes: (baser >> 48 & 0x1F) as u8 }
}
/// `InnerCache` `0b111`, read-allocate write-allocate write-back, with
# its-table-entries
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -243,7 +243,7 @@
impl Backing {
/// The entries a flat table of `pages` of its pages holds.
pub const fn entries(self, pages: u16) -> u64 {
- pages as u64 * self.page.bytes() / self.entry_bytes as u64
+ pages as u64 * self.page.bytes()
}
/// The fewest pages that hold `entries`. `None` for none, or more than
# its-table-pages-rounded-down
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -252,7 +252,7 @@
let Some(bytes) = entries.checked_mul(self.entry_bytes as u64) else {
return None;
};
- let pages = bytes.div_ceil(self.page.bytes());
+ let pages = bytes / self.page.bytes();
if pages >= 1 && pages <= 256 {
Some(pages as u16)
} else {
# its-table-pages-unbounded
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -253,7 +253,7 @@
return None;
};
let pages = bytes.div_ceil(self.page.bytes());
- if pages >= 1 && pages <= 256 {
+ if pages >= 1 {
Some(pages as u16)
} else {
None
# its-baser-pages-bound
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -265,7 +265,7 @@
/// `Page_Size` [9:8], `Size` [7:0] the pages minus one. `None` for no
/// page or more than the 256 the field counts.
pub const fn baser(self, at: Phys<16>, pages: u16) -> Option<u64> {
- if pages == 0 || pages > 256 {
+ if pages == 0 {
return None;
}
let size = match self.page {
# its-baser-size-not-minus-one
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -273,7 +273,7 @@
PageSize::K16 => 0b01,
PageSize::K64 => 0b10,
};
- Some(VALID | CACHED | at.get() | size << 8 | (pages - 1) as u64)
+ Some(VALID | CACHED | at.get() | size << 8 | (pages as u64 & 0xFF))
}
}
# its-baser-page-size-64k
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -271,7 +271,7 @@
let size = match self.page {
PageSize::K4 => 0b00,
PageSize::K16 => 0b01,
- PageSize::K64 => 0b10,
+ PageSize::K64 => 0b11,
};
Some(VALID | CACHED | at.get() | size << 8 | (pages - 1) as u64)
}
# its-baser-not-valid
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -273,7 +273,7 @@
PageSize::K16 => 0b01,
PageSize::K64 => 0b10,
};
- Some(VALID | CACHED | at.get() | size << 8 | (pages - 1) as u64)
+ Some(CACHED | at.get() | size << 8 | (pages - 1) as u64)
}
}
# its-cache-field
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -237,7 +237,7 @@
/// `InnerCache` `0b111`, read-allocate write-allocate write-back, with
/// `OuterCache` zero, as the inner; `Shareability` [11:10] `0b01`, inner
/// shareable. `GITS_BASER<n>` and `GITS_CBASER` hold them at the same bits.
-const CACHED: u64 = 0b111 << 59 | 0b01 << 10;
+const CACHED: u64 = 0b111 << 56 | 0b01 << 10;
const VALID: u64 = 1 << 63;
impl Backing {
# its-queue-full-is-empty
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -325,6 +325,6 @@
/// One more command would make the writer's offset the reader's, which
/// reads as empty: the queue holds one command fewer than its bytes do.
pub const fn is_full(self, cwriter: u64, creadr: u64) -> bool {
- self.after(cwriter) == self.offset(creadr) as u64
+ self.offset(cwriter) == self.offset(creadr) && false
}
}
# its-queue-full-reads-the-register
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -325,6 +325,6 @@
/// One more command would make the writer's offset the reader's, which
/// reads as empty: the queue holds one command fewer than its bytes do.
pub const fn is_full(self, cwriter: u64, creadr: u64) -> bool {
- self.after(cwriter) == self.offset(creadr) as u64
+ self.after(cwriter) == creadr
}
}
# its-queue-empty-reads-the-registers
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -319,7 +319,7 @@
/// The ITS has read every command: the two registers' offsets are equal.
pub const fn is_empty(self, cwriter: u64, creadr: u64) -> bool {
- self.offset(cwriter) == self.offset(creadr)
+ cwriter == creadr
}
/// One more command would make the writer's offset the reader's, which
# its-queue-no-wrap
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -314,7 +314,7 @@
/// What `GITS_CWRITER` is written with once the command at its offset is
/// in memory: the offset after, wrapping at the queue's end.
pub const fn after(self, cwriter: u64) -> u64 {
- ((self.offset(cwriter) + 32) % self.bytes) as u64
+ (self.offset(cwriter) + 32) as u64
}
/// The ITS has read every command: the two registers' offsets are equal.
# its-queue-after-reads-the-register
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -314,7 +314,7 @@
/// What `GITS_CWRITER` is written with once the command at its offset is
/// in memory: the offset after, wrapping at the queue's end.
pub const fn after(self, cwriter: u64) -> u64 {
- ((self.offset(cwriter) + 32) % self.bytes) as u64
+ ((cwriter as u32).wrapping_add(32) % self.bytes) as u64
}
/// The ITS has read every command: the two registers' offsets are equal.
# its-queue-offset-field
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -308,7 +308,7 @@
/// The byte offset an offset register names: its `Offset` field alone,
/// and inside the queue whatever the ITS wrote there.
pub const fn offset(self, register: u64) -> u32 {
- (register & 0xF_FFE0) as u32 % self.bytes
+ (register & 0xF_FFFF) as u32 % self.bytes
}
/// What `GITS_CWRITER` is written with once the command at its offset is
# its-queue-offset-unbounded
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -308,7 +308,7 @@
/// The byte offset an offset register names: its `Offset` field alone,
/// and inside the queue whatever the ITS wrote there.
pub const fn offset(self, register: u64) -> u32 {
- (register & 0xF_FFE0) as u32 % self.bytes
+ (register & 0xF_FFE0) as u32
}
/// What `GITS_CWRITER` is written with once the command at its offset is
# its-cbaser-size
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -302,7 +302,7 @@
/// `Physical_Address` [51:12] with its low four bits zero, `Size` [7:0]
/// the pages minus one.
pub const fn cbaser(self, at: Phys<16>) -> u64 {
- VALID | CACHED | at.get() | (self.bytes / 4096 - 1) as u64
+ VALID | CACHED | at.get() | (self.bytes / 4096) as u64 & 0xFF
}
/// The byte offset an offset register names: its `Offset` field alone,
# its-offset-cwriter
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -30,7 +30,7 @@
pub const GITS_CTLR: usize = 0x0000;
pub const GITS_TYPER: usize = 0x0008;
pub const GITS_CBASER: usize = 0x0080;
-pub const GITS_CWRITER: usize = 0x0088;
+pub const GITS_CWRITER: usize = 0x0084;
pub const GITS_CREADR: usize = 0x0090;
/// `GITS_BASER<n>`, n = 0 to 7 (§12.19.1): one per table the ITS may ask
# its-baser-stride
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -37,7 +37,7 @@
/// memory for.
pub const fn gits_baser(n: usize) -> Option<usize> {
if n < 8 {
- Some(0x0100 + 8 * n)
+ Some(0x0100 + 4 * n)
} else {
None
}
# its-translation-frame
--- a/toyos-its/src/lib.rs
+++ b/toyos-its/src/lib.rs
@@ -47,7 +47,7 @@
/// `GITS_TRANSLATER` is at 0x0040 of it (Table 12-34): a function's message
/// is one 32-bit write of its EventID there, and the bus says which device
/// wrote it.
-pub const TRANSLATION_FRAME: u64 = 0x1_0000;
+pub const TRANSLATION_FRAME: u64 = 0x2_0000;
pub const GITS_TRANSLATER: u64 = 0x0040;
/// `GITS_CTLR.Enabled` [0] (§12.19.4). |
|
Mutations at f8022b7, round 2, of The patches# lpi-first
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -6,7 +6,7 @@
/// The first LPI's INTID (§2.2): everything below is an SGI, a PPI, an SPI
/// or special.
-pub const FIRST: u32 = 8192;
+pub const FIRST: u32 = 8191;
/// Offsets in a redistributor's `RD_base` frame (§12.10, Table 12-27).
pub const GICR_PROPBASER: usize = 0x0070;
# lpi-past-space
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -117,7 +117,7 @@
impl Space {
/// `intid` as an LPI of this space.
pub const fn lpi(self, intid: u32) -> Option<Lpi> {
- if intid >= FIRST && intid - FIRST < self.lpis {
+ if intid >= FIRST {
Some(Lpi(intid))
} else {
None
# lpi-config-res1
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -45,7 +45,7 @@
/// One LPI's byte in the configuration table (Table 5-1): the priority's
/// upper six bits in [7:2], bit [1] RES1, and the enable in bit [0].
pub const fn configuration(priority: u8, enabled: bool) -> u8 {
- priority & 0xFC | 0b10 | enabled as u8
+ priority & 0xFC | enabled as u8
}
/// The two tables laid out for INTIDs of `id_bits` bits, which the
# lpi-config-priority-bits
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -45,7 +45,7 @@
/// One LPI's byte in the configuration table (Table 5-1): the priority's
/// upper six bits in [7:2], bit [1] RES1, and the enable in bit [0].
pub const fn configuration(priority: u8, enabled: bool) -> u8 {
- priority & 0xFC | 0b10 | enabled as u8
+ priority | 0b10 | enabled as u8
}
/// The two tables laid out for INTIDs of `id_bits` bits, which the
# lpi-config-index
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -38,7 +38,7 @@
/// Where its byte is in the configuration table: the table's first byte
/// is INTID 8192's (§5.1.1).
pub const fn configuration_index(self) -> usize {
- (self.0 - FIRST) as usize
+ self.0 as usize
}
}
# lpi-pending-bytes
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -86,7 +86,7 @@
/// One bit for every INTID, the first 8192 included.
pub const fn pending_bytes(self) -> u64 {
- (1 << self.id_bits) / 8
+ ((1 << self.id_bits) - FIRST as u64) / 8
}
/// `GICR_PROPBASER` (§12.11.33) for the configuration table at `table`:
# lpi-config-bytes
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -81,7 +81,7 @@
/// One byte for every INTID from 8192 that `id_bits` bits number.
pub const fn configuration_bytes(self) -> u64 {
- (1 << self.id_bits) - FIRST as u64
+ 1 << self.id_bits
}
/// One bit for every INTID, the first 8192 included.
# lpi-layout-floor
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -68,7 +68,7 @@
/// [15:11], where not zero, counts the LPIs there are from 8192 on.
pub const fn new(gicd_typer: u32, id_bits: u8) -> Option<Self> {
let widest = (gicd_typer >> 19 & 0x1F) as u8 + 1;
- if gicd_typer & 1 << 17 == 0 || id_bits < 14 || id_bits > widest {
+ if gicd_typer & 1 << 17 == 0 || id_bits > widest {
return None;
}
let numbered = (1u64 << id_bits) - FIRST as u64;
# lpi-layout-past-the-distributor
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -68,7 +68,7 @@
/// [15:11], where not zero, counts the LPIs there are from 8192 on.
pub const fn new(gicd_typer: u32, id_bits: u8) -> Option<Self> {
let widest = (gicd_typer >> 19 & 0x1F) as u8 + 1;
- if gicd_typer & 1 << 17 == 0 || id_bits < 14 || id_bits > widest {
+ if gicd_typer & 1 << 17 == 0 || id_bits < 14 || id_bits > 32 {
return None;
}
let numbered = (1u64 << id_bits) - FIRST as u64;
# lpi-layout-without-lpis
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -68,7 +68,7 @@
/// [15:11], where not zero, counts the LPIs there are from 8192 on.
pub const fn new(gicd_typer: u32, id_bits: u8) -> Option<Self> {
let widest = (gicd_typer >> 19 & 0x1F) as u8 + 1;
- if gicd_typer & 1 << 17 == 0 || id_bits < 14 || id_bits > widest {
+ if id_bits < 14 || id_bits > widest {
return None;
}
let numbered = (1u64 << id_bits) - FIRST as u64;
# lpi-lpis-bit
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -68,7 +68,7 @@
/// [15:11], where not zero, counts the LPIs there are from 8192 on.
pub const fn new(gicd_typer: u32, id_bits: u8) -> Option<Self> {
let widest = (gicd_typer >> 19 & 0x1F) as u8 + 1;
- if gicd_typer & 1 << 17 == 0 || id_bits < 14 || id_bits > widest {
+ if gicd_typer & 1 << 16 == 0 || id_bits < 14 || id_bits > widest {
return None;
}
let numbered = (1u64 << id_bits) - FIRST as u64;
# lpi-idbits-field
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -67,7 +67,7 @@
/// LPI, or above its INTIDs' (`IDbits` [23:19] plus one). Its `num_LPIs`
/// [15:11], where not zero, counts the LPIs there are from 8192 on.
pub const fn new(gicd_typer: u32, id_bits: u8) -> Option<Self> {
- let widest = (gicd_typer >> 19 & 0x1F) as u8 + 1;
+ let widest = (gicd_typer >> 18 & 0x1F) as u8 + 1;
if gicd_typer & 1 << 17 == 0 || id_bits < 14 || id_bits > widest {
return None;
}
# lpi-idbits-minus-one
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -67,7 +67,7 @@
/// LPI, or above its INTIDs' (`IDbits` [23:19] plus one). Its `num_LPIs`
/// [15:11], where not zero, counts the LPIs there are from 8192 on.
pub const fn new(gicd_typer: u32, id_bits: u8) -> Option<Self> {
- let widest = (gicd_typer >> 19 & 0x1F) as u8 + 1;
+ let widest = (gicd_typer >> 19 & 0x1F) as u8;
if gicd_typer & 1 << 17 == 0 || id_bits < 14 || id_bits > widest {
return None;
}
# lpi-num-lpis-ignored
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -74,7 +74,7 @@
let numbered = (1u64 << id_bits) - FIRST as u64;
let counted = match gicd_typer >> 11 & 0x1F {
0 => numbered,
- count => 2u64 << count,
+ _ => numbered,
};
Some(Self { id_bits, lpis: if counted < numbered { counted } else { numbered } as u32 })
}
# lpi-num-lpis-field
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -72,7 +72,7 @@
return None;
}
let numbered = (1u64 << id_bits) - FIRST as u64;
- let counted = match gicd_typer >> 11 & 0x1F {
+ let counted = match gicd_typer >> 10 & 0x1F {
0 => numbered,
count => 2u64 << count,
};
# lpi-num-lpis-count
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -74,7 +74,7 @@
let numbered = (1u64 << id_bits) - FIRST as u64;
let counted = match gicd_typer >> 11 & 0x1F {
0 => numbered,
- count => 2u64 << count,
+ count => 1u64 << count,
};
Some(Self { id_bits, lpis: if counted < numbered { counted } else { numbered } as u32 })
}
# lpi-count-past-the-tables
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -76,7 +76,7 @@
0 => numbered,
count => 2u64 << count,
};
- Some(Self { id_bits, lpis: if counted < numbered { counted } else { numbered } as u32 })
+ Some(Self { id_bits, lpis: counted as u32 })
}
/// One byte for every INTID from 8192 that `id_bits` bits number.
# lpi-space-of-any-idbits
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -99,7 +99,7 @@
/// its `IDbits` is not what [`Layout::propbaser`] wrote, which a
/// redistributor that holds the register as its own answers.
pub const fn space(self, propbaser: u64) -> Option<Space> {
- if (propbaser & 0x1F) as u8 == self.id_bits - 1 {
+ if true {
Some(Space { lpis: self.lpis })
} else {
None
# lpi-space-idbits-mask
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -99,7 +99,7 @@
/// its `IDbits` is not what [`Layout::propbaser`] wrote, which a
/// redistributor that holds the register as its own answers.
pub const fn space(self, propbaser: u64) -> Option<Space> {
- if (propbaser & 0x1F) as u8 == self.id_bits - 1 {
+ if (propbaser & 0xFF) as u8 == self.id_bits - 1 {
Some(Space { lpis: self.lpis })
} else {
None
# lpi-propbaser-idbits
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -92,7 +92,7 @@
/// `GICR_PROPBASER` (§12.11.33) for the configuration table at `table`:
/// `Physical_Address` [51:12] and `IDbits` [4:0], the bits minus one.
pub const fn propbaser(self, table: Phys<12>) -> u64 {
- CACHED | table.get() | (self.id_bits - 1) as u64
+ CACHED | table.get() | self.id_bits as u64
}
/// The LPIs of a redistributor that reads `propbaser` back: `None` where
# lpi-pendbaser-not-zeroed
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -129,5 +129,5 @@
/// all zeroes: `Physical_Address` [51:16], and `PTZ` [62], which says so and
/// lets the redistributor not read it.
pub const fn pendbaser(table: Phys<16>) -> u64 {
- 1 << 62 | CACHED | table.get()
+ CACHED | table.get()
}
# lpi-cache-field
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -59,7 +59,7 @@
/// `InnerCache` [9:7] `0b111`, read-allocate write-allocate write-back, with
/// `OuterCache` [58:56] zero, as the inner; `Shareability` [11:10] `0b01`,
/// inner shareable. Both base registers hold them at the same bits.
-const CACHED: u64 = 0b111 << 7 | 0b01 << 10;
+const CACHED: u64 = 0b111 << 8 | 0b01 << 10;
impl Layout {
/// `GICD_TYPER` (§12.9.38) judged: `None` where the distributor takes no
# lpi-processor-number
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -22,7 +22,7 @@
/// `GICR_TYPER.Processor_Number` [23:8]: how an ITS whose `GITS_TYPER.PTA`
/// is clear names this redistributor.
pub const fn processor_number(typer: u64) -> u16 {
- (typer >> 8) as u16
+ (typer >> 16) as u16
}
/// An LPI's INTID, one the distributor and its redistributor both take:
# lpi-offset-propbaser
--- a/toyos-its/src/lpi.rs
+++ b/toyos-its/src/lpi.rs
@@ -9,7 +9,7 @@
pub const FIRST: u32 = 8192;
/// Offsets in a redistributor's `RD_base` frame (§12.10, Table 12-27).
-pub const GICR_PROPBASER: usize = 0x0070;
+pub const GICR_PROPBASER: usize = 0x0078;
pub const GICR_PENDBASER: usize = 0x0078;
/// `GICR_CTLR.EnableLPIs` [0] (§12.11.2): from here the redistributor reads |
|
Review of #798 at Oracles fetched for this round from Arm's documentation service ( Growth. Earlier BLOCKERs
Earlier NOTEsAll closed: Checked this round
BLOCKERNone. NOTE
What the landing head must showThe branch must merge LAND AFTER NAMED CHANGES |
…mapping index past its array is refused by name DEN 0049 E.g Table 13 makes the DeviceID mapping index "an index into the array of ID mapping". Where the node says the field is valid (the flag from node revision 5, an unwired control interrupt before it) an index at or past the array's count named no entry and read as a node with no mapping of its own, which routed: malformed firmware failing open. `iort` now refuses it as `IortRefused::OwnMapping`. `Route::Translated` named a stream without saying whether anyone else's transactions arrive under it. Overlap was judged on input IDs within the asked segment, so two RID ranges of one root complex, two segments, or a named component mapped onto the same streams of one SMMUv3 each answered `Translated` with the same stream, and a claim attaching its domain there would hand another function its DMA. The IORT holds every mapping that reaches the unit, so `route` now walks them once more and refuses a stream any other mapping puts out to the same unit as `IortRefused::SharedStream`, whatever the other node's type. A node type `check` does not decode has its ID array held to Table 4's header and its own length before that walk reads it. `IORT_NEEDED` leaves the crate's exports; nothing outside `iort.rs` reads it. The duplicated-declarations issue names its owner as `issues/toyos-runs-on-arm64.md`'s stage 6. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
…d the installed NVMe image (#797), into the IORT decode and the SMMUv3 and ITS encodings Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C
|
Round-3 mutation patches, each applied to
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -434,7 +434,7 @@
return Err(IortRefused::Mappings { at, count, offset });
}
let own = self.own(raw);
- if let Some(index) = own.filter(|index| *index >= count) {
+ if let Some(index) = own.filter(|_| false) {
return Err(IortRefused::OwnMapping { at, index, count });
}
for index in (0..count).filter(|index| Some(*index) != own) {
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -434,7 +434,7 @@
return Err(IortRefused::Mappings { at, count, offset });
}
let own = self.own(raw);
- if let Some(index) = own.filter(|index| *index >= count) {
+ if let Some(index) = own.filter(|index| *index > count) {
return Err(IortRefused::OwnMapping { at, index, count });
}
for index in (0..count).filter(|index| Some(*index) != own) {
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -251,7 +251,6 @@
_ => return Err(IortRefused::Output { at: unit.at, reference: mapping.reference }),
},
};
- self.alone(unit, (root.at, index), id)?;
Ok(Route::Translated { smmu, stream: id, its })
}
_ => Err(IortRefused::Output { at: root.at, reference: mapping.reference }),
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -306,7 +306,7 @@
let mapping = self.mapping(raw, index).ok_or(IortRefused::Mappings { at, count, offset })?;
let last = if mapping.single { 0 } else { mapping.span };
let reaches = stream >= mapping.output && stream - mapping.output <= last;
- if reaches && mapping.reference as usize == unit.at {
+ if reaches {
return Err(IortRefused::SharedStream { stream, at });
}
}
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -302,7 +302,7 @@
if count != 0 && ((offset as usize) < NODE_HEADER || end > raw.len as u64) {
return Err(IortRefused::Mappings { at, count, offset });
}
- for index in (0..count).filter(|index| (at, *index) != by) {
+ for index in (0..count).filter(|_| true) {
let mapping = self.mapping(raw, index).ok_or(IortRefused::Mappings { at, count, offset })?;
let last = if mapping.single { 0 } else { mapping.span };
let reaches = stream >= mapping.output && stream - mapping.output <= last;
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -302,7 +302,7 @@
if count != 0 && ((offset as usize) < NODE_HEADER || end > raw.len as u64) {
return Err(IortRefused::Mappings { at, count, offset });
}
- for index in (0..count).filter(|index| (at, *index) != by) {
+ for index in (0..count).filter(|index| *index != by.1) {
let mapping = self.mapping(raw, index).ok_or(IortRefused::Mappings { at, count, offset })?;
let last = if mapping.single { 0 } else { mapping.span };
let reaches = stream >= mapping.output && stream - mapping.output <= last;
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -304,7 +304,7 @@
}
for index in (0..count).filter(|index| (at, *index) != by) {
let mapping = self.mapping(raw, index).ok_or(IortRefused::Mappings { at, count, offset })?;
- let last = if mapping.single { 0 } else { mapping.span };
+ let last = mapping.span;
let reaches = stream >= mapping.output && stream - mapping.output <= last;
if reaches && mapping.reference as usize == unit.at {
return Err(IortRefused::SharedStream { stream, at });
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -305,7 +305,7 @@
for index in (0..count).filter(|index| (at, *index) != by) {
let mapping = self.mapping(raw, index).ok_or(IortRefused::Mappings { at, count, offset })?;
let last = if mapping.single { 0 } else { mapping.span };
- let reaches = stream >= mapping.output && stream - mapping.output <= last;
+ let reaches = stream >= mapping.output && stream - mapping.output < last;
if reaches && mapping.reference as usize == unit.at {
return Err(IortRefused::SharedStream { stream, at });
}
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -299,7 +299,7 @@
// [`Iort::check`] placed the arrays of the types it decodes; a
// type it does not is held to Table 4's header and its own length.
let end = u64::from(offset) + u64::from(count) * MAPPING as u64;
- if count != 0 && ((offset as usize) < NODE_HEADER || end > raw.len as u64) {
+ if count != 0 && end > raw.len as u64 {
return Err(IortRefused::Mappings { at, count, offset });
}
for index in (0..count).filter(|index| (at, *index) != by) {
--- a/toyos-acpi/src/iort.rs
+++ b/toyos-acpi/src/iort.rs
@@ -299,7 +299,7 @@
// [`Iort::check`] placed the arrays of the types it decodes; a
// type it does not is held to Table 4's header and its own length.
let end = u64::from(offset) + u64::from(count) * MAPPING as u64;
- if count != 0 && ((offset as usize) < NODE_HEADER || end > raw.len as u64) {
+ if count != 0 && (offset as usize) < NODE_HEADER {
return Err(IortRefused::Mappings { at, count, offset });
}
for index in (0..count).filter(|index| (at, *index) != by) { |
|
Round 3, answering #798 (comment). Head NOTE 1, an own-mapping index past the array — fixed. NOTE 2, a stream another requester shares — fixed by refusing. The IORT holds every mapping into a unit, so no record was needed. NOTE 3, NOTE 4, the issue's owner — fixed. Gates at Two things this round changes beyond the NOTEs' words, both fail-closed and both in the body's "unsure" list. A revision 4 SMMUv3 with an unwired GSIV and no ID mapping now refuses the whole table, because its index holds and names nothing. And a reserved memory range node mapping a stream counts as a sharer of it. |
|
CI at |
Stage G1 of the ARM desktop, on
issues/toyos-runs-on-arm64.md's stage 6: host-only, and no file underkernel/. The owner's words for the order: "No, isolation first" — the IOMMU is built before any ARM userland driver touches a device. This is what the kernel's SMMUv3 unit (G2) and its ITS (G3) are built on.What was measured first
QEMU 11.1.1's
virtunder HVF with edk2-stable202408 and no operating system in the guest: the firmware was left to reach its shell, guest RAM was written out with the monitor'spmemsave, and the tables were walked host-side from the RSDP. Both QEMUs exited onquit.toyos-acpi/fixtures/qemu-11.1.1-virt/SOURCEhas the commands.gic-version=3,iommu=smmuv3(the hypervisor's GIC)gic-version=3,its=on,iommu=smmuv3,kernel-irqchip=off0x09050000,COHACC override, GSIVs event 106, PRI 107, GERR 109, sync 108, DeviceID mapping index 0, no ID mapping0..=0xffffto the ITS, DeviceID = StreamID0x00..=0xffto the SMMU, StreamID = RID; nothing else mapped0x100..=0xffffstraight to the ITS, DeviceID = RID0x08080000The plan's table read the four GSIVs as "106 to 109 (event, PRI, gerror, sync)"; the node's order is event, PRI, GERR, sync and its values are 106, 107, 109, 108. No node type beyond the ITS, the root complex and the SMMUv3 appears in either mode, so the stop condition did not arise.
What changed, by decision
toyos-acpi: the IORT (src/iort.rs).iort(phys, rsdp)answers anIortevery node of which it has walked, or a named refusal.Iort::nodes()gives each node asIts { id },RootComplex { segment },Smmuv3(Smmuv3)orOther(type);Iort::route(segment, rid)givesTranslated { smmu, stream, its: Option<ItsDevice> },Untranslated(ItsDevice)orUnmapped.OwnMapping).SharedStream).Translatedwith the samestream, and G2 attaching a claim's domain there would hand the other requester the claim's DMA. The IORT holds every mapping that reaches a unit, soroutewalks every node and its mappings once more and refusesSharedStream { stream, at }where any mapping but the requester's own puts that stream out to that unit, whatever the other node's type: a single mapping (a named component's) counts its output base alone, and a mapping to an ITS or to another SMMUv3 is no sharer. A node typecheckdoes not decode has its ID array held to Table 4's header and its own length before that walk reads it, refused asMappingsotherwise. The stream is judged last, after the SMMUv3's onward reference, so a table that is malformed there still answersOutput.virt's node is revision 4 with all four wired, so its index is ignored and its one mapping routes streams. A revision 4 unit with no PRI interrupt has a zero PRI GSIV and so an index that holds, which is what E.e's flag was added to end: the entry it names stops routing, a claim behind it findsits: Noneand is refused. That is fail-closed, and it is not onvirt. Where the index holds by either rule and names no entry, the table isOwnMapping: E.g calls it "an index into the array of ID mapping", and one past the array is malformed firmware, not a node with no mapping of its own.virt. A single mapping in a root complex, or in an SMMUv3 beside its own: Table 6 names both node types among those the flag is valid in, and has it put every input ID out as one. And an ITS group of more than one ITS under a table of revision 5 or 6, which was legal until issue E.g fixed the count at 1. Nothing in the gate routes either; each isSingleMappingorItsGroupand not a silent skip.iortreads each node and each mapping once, and a route walks the nodes once to find its root complex and once for each of the two references it may follow. A reference nothing routes through is not judged.opening_a_table_and_routing_a_requester_each_read_it_a_bounded_number_of_timescounts the bytes read of a 417,236-byte table of 500 nodes and 19,960 mappings: 824,594 to open and 14,812 to route, held to three times its length and an eighth of it. With each reference followed at open again the open reads 120,744,274. Both of the review's named ways (resolve once at open, index the nodes) need storage for node offsets, which here would be an array with a cap on the nodes of a table; I took neither for that reason.Overlapwhether it sits in the same node, a second root complex of the segment, or the SMMU's own array.toyos-acpi/src/madt.rsismain's.git diff origin/main -- toyos-acpi/src/madt.rsprints nothing.msi_controllers,MsiController,MsiFrame,SpiRangeand theStructuresplit are deleted with their three tests. The MADT's ITS entry isMadtEntry::Itsonmainalready; two tests here read it out ofvirt's two MADTs withmadt_entriesas it stands. The stage that owns the kernel's exhaustive matches adds aMadtEntryvariant if it needs the MSI frame at all.toyos-phys, new:Phys<const ALIGN>has one home. Both crates declared it. Neither may depend on the other (an ITS is no part of an SMMU),toyos-bootmapmay change only by a re-export, andtoyos-abiis outside the fence, so the home is a third crate of one type: an address aligned to1 << ALIGNand below 2^48. It gainsPhys::of(word), the address a word holds in its bits[47:ALIGN], whichtoyos-smmureads a table descriptor back with.toyos-smmu. One configuration and no other: a stream aborts, or is translated by stage 1 alone through one context descriptor under NS-EL1, with 4 KiB-granule VMSAv8-64 tables over a 48-bit input.IDR5.OASis private toUnit, andstream_table,command_queueandevent_queueanswerNonefor a table or queue any byte of which is at or past1 << OAS;Ste::stage1,Cd::new,table::nextandtable::plananswerNonefor anS1ContextPtr, aTTB0, a next table or a leaf's output past it. The check takes the unit each time, so two units of different sizes cannot lend each other an address.SteandCdhold their words privately;Ste::ABORTandSte::stage1are the only ways to anSte, andwords()reads one.toyos-bootmap's.table::planbuilds a leaf fromtoyos_bootmap::aarch64::blockandpage,nextfromtable, andMAIR0is the low word of itsMAIR;toyos-bootmapchanges by one word,pubonPXN, which changes no byte anything builds. Whattoyos-bootmapdoes not declare stays here:AP[1],AP[2],nG, the two bits a descriptor is read back by, and the level index.Unit::command_queueanswers its base register and aCommands;Unit::event_queuea base and anEvents.Events::after(cons, prod)is whatSMMU_EVENTQ_CONSis written with: the next position andOVACKFLGequal to theOVFLGthatprodwas read with, which is §7.4's acknowledgement and can never forge an overflow;Events::overflowed(prod, cons)says records were lost.Commands::aftercannot be handed an event index.probe(idr0, idr1, idr5, coherent_override)takes the IORT'sSmmuv3::coherent_override, which stands forIDR0.COHACCwhere it is set (DEN 0049 Table 14), and refuses a unit neither calls coherent asLacks::CoherentAccess:CR1_WRITE_BACKand every cacheability written here assume it.Signal::Sev(valid only underIDR0.SEV, whichUnitdoes not carry),Command::ForgetContext(CMD_CFGI_CD: with one context descriptor behind each entry,CMD_CFGI_STEforgets both), the publicoutput_bitsandcoherent.Signal::NoneandSignal::Irqboth stay: aCMD_SYNCis waited on by the sync GSIV the IORT gives, or by readingSMMU_CMDQ_CONSwhere that interrupt is not yet routed, and G2 deletes the one it does not issue.toyos-its. Physical LPIs through flat tables. The device table's and the ITT's entries are IMPLEMENTATION DEFINED (IHI 0069 §5.2.3, §5.2.4) and written only by the ITS, so no entry is encoded.EventBits::event(id)answers anEventinside its device's table;MAPTI,INVandDISCARDtake one.Its::collections(in_table)answers how many collections there are — the collection table's entries, withGITS_TYPER.HCCwhere there is no table orCCTcounts both, and no more than an ICID of 16 bits or ofCIDbitsunderCILnumbers (§5.2.2, §5.3.1) — andCollections::collection(id)aCollection;MAPCandMAPTItake one.lpi::Layout::new(gicd_typer, bits)isNoneunless the distributor takes LPIs (LPIS) and has that many INTID bits (IDbits), and counts the LPIs bynum_LPIs;Layout::space(propbaser)is theSpaceof a redistributor that readGICR_PROPBASERback with theIDbitswritten, and only aSpacemakes anLpi. The 24-bit cap of round 1, a bound of mine, is gone.CommandQueue::is_empty,is_fullandaftertakeGITS_CWRITERandGITS_CREADRas read and mask them toOffset, soStalledor a reserved bit beside an offset is the same offset.Backing: whatGITS_BASER<n>backs and its page size, withentries(pages),pages(entries)andbaser(at, pages), so the device table's and the collection table's sizes are not arithmetic in the driver.Its::collections_heldas a public field,CTLR_QUIESCENT,Lpi::pending_bit(the pending table is zeroed andPTZsays so; nothing writes a bit of it), andGICR_CTLR's andGICR_TYPER's offsets, whichkernel/src/arch/aarch64/irqchip.rsdeclares and G3 edits.Siblings that stay, recorded.
issues/the-smmuv3-and-its-crates-declare-what-the-aarch64-kernel-also-declares.md: the stage 1 bits and level index besidekernel/src/arch/aarch64/paging.rs, andGICR_CTLR.EnableLPIs,GICR_TYPER.PLPISandProcessor_Numberbesidekernel/gicv3andirqchip.rs. Unifying either means editingkernel/; the owner isissues/toyos-runs-on-arm64.md's stage 6 (its SMMUv3 unit and its ITS), and the exit is tworgcommands that print nothing.Left out on purpose, since nothing in the plan's gate needs it: the two-level stream table (a linear one is always supported, and a StreamID past it aborts with
C_BAD_STREAMID),CMD_TLBI_NH_VA(an unmap invalidates its domain's ASID), stalls, substreams, ATS, PRI, stage 2, the unit's own MSIs, and the ITS'sMAPI,MOVI,INVALLand every vPE command.What G2 and G3 build on each type
toyos_acpi::Iort::nodes,Smmuv3 { base, coherent_override, event, gerror, sync }Option<NonZeroU32>: a unit that signals by MSI has none, and is refused there)Iort::route→Route::Translated { stream, .. }Route::Untranslated,Route::Unmapped,IortRefused::SharedStreamvirt), or under a stream another requester sharesRoute::Translated { its: Some(ItsDevice { its, device }) }MAPDandMAPTIare issued under;its: None(every function in the hypervisor-GIC mode) is the claim's refusaltoyos_acpi::madt_entries→MadtEntry::Its { id, base }(main's)toyos_smmu::unit::probe(idr0, idr1, idr5, coherent_override)→Unit/LacksUnitis then the only way to anAsid, a stream table or queue base, a translatingSte, aCdand a table planunit::*offsets and values,active_errors,command_errorGBPAabort,CR1,CR2, the bases,CR0),GERRORserviceconfig::Ste::ABORT,Ste::stage1(Phys<6>, &Unit)config::Cd::new(Phys<12>, Asid, &Unit)Unit::command_queue→Commands;queue::Command,SignalCMD_SYNCUnit::event_queue→Events;queue::event→Event { stream, code, attempt }pcidev::note_fault, each consumed with its overflow acknowledgedtable::plan(at, Leaf::Memory(Phys<21>, Access), &Unit),next,entrytable::plan(at, Leaf::Doorbell(Phys<12>), &Unit)GITS_TRANSLATER's page in each claimed domaintoyos_its::probe→Its;table→Backing;CommandQueueIts::events→EventBits→Event;Its::itt_bytes;Its::collections→Collection;Its::target→Targetcommand::CommandMAPCper CPU,MAPD/MAPTI/INVper claim,DISCARDand unmap on release,SYNClpi::Layout→Space→Lpi;configuration,pendbaserTRANSLATION_FRAME,GITS_TRANSLATERThe checks of this high-risk code
It is an isolation boundary and a device's and firmware's input.
Independent oracles. The specifications, fetched from Arm's documentation service this round: IHI 0070 H.a (SMMUv3), IHI 0069 H.b (GIC), DEN 0049 E.b, E.c, E.d, E.e, E.f and E.g (IORT), DDI 0487 M.d (Tables D8-50, D8-52 and D8-63, for the descriptor bits). ACPI 6.5 is not cited by anything left in the diff. And a differential implementation for the decoder: QEMU's own table generator, whose bytes are the fixtures. No other kernel's source was read.
What each issue of DEN 0049 states, read from the
Revisionrow of each node's table:The decoder takes tables 5..=7, SMMUv3 nodes 4..=5, root complex nodes 3..=4 (QEMU publishes a revision 3 node under a revision 5 table) and ITS node 1. Round 1's body said no older issue could be read; that was false, and all six are read here.
How each position was confirmed. The PDFs are read as text extracted with
pypdf; no renderer is on the machine. A field heading and a register-summary row are text and unambiguous. A figure comes out as labels, so its positions are read from each label's x coordinate beside the bit ruler's.IDR00x0,IDR10x4,IDR50x14,CR00x20,CR0ACK0x24,CR10x28,CR20x2C,GBPA0x44,IRQ_CTRL0x50,IRQ_CTRLACK0x54,GERROR0x60,GERRORN0x64,STRTAB_BASE0x80,STRTAB_BASE_CFG0x88,CMDQ_BASE0x90,CMDQ_PROD0x98,CMDQ_CONS0x9C,EVENTQ_BASE0xA0EVENTQ_PROD0x100A8,EVENTQ_CONS0x100ACOVFLG[31],OVACKFLG[31];IDR0.COHACC[4];IDR5.OAS[2:0]GITS_CTLR0x0,GITS_TYPER0x8,GITS_CBASER0x80,GITS_CWRITER0x88,GITS_CREADR0x90,GITS_BASER<n>0x100..0x138GITS_TRANSLATER0x40 of the frame atITS_base + 0x010000GICR_PROPBASER0x70,GICR_PENDBASER0x78GITS_TYPER:CCT[2],HCC[31:24],CIDbits[35:32],CIL[36];GICD_TYPER:num_LPIs[15:11],LPIS[17],IDbits[23:19];GICR_PROPBASER.IDbits[4:0];GITS_CREADR/CWRITER.Offset[19:5],Stalled[0]DISCARD: DW0 DeviceID [63:32], RES0 [31:8], 0x0F [7:0]; DW1 RES0 [63:32], EventID [31:0]pypdfreports no position for the EventID label, so its text matrix was read from the page's content stream: x=414.6 on DW1's row (y=502.5), right of the 32/31 mark. The prose gives the arguments as "DISCARD DeviceID, EventID"INV: the same layout under 0x0CDeviceID mapping indexat 64; flags bit 4AttrIndx[4:2],AP[1][6],AP[2][7],SH[9:8],AF[10],nG[11],PXN[53],UXN[54];AP[2:1]01read-write at both levels and11read-only at bothEach has a test that states the layout:
the_registers_sit_where_the_register_overview_has_them(toyos-smmu),the_its_registers_sit_where_tables_12_33_and_12_34_have_them,the_redistributors_lpi_registers_sit_where_table_12_27_has_themandinv_and_discard_hold_a_device_and_an_event_and_nothing_else(toyos-its). Every section number the three crates cite was looked up against its heading. The encoding tests write the specification's positions as(msb, lsb, value)triples and compare the whole value: they hold a constant against drift, and the oracle is the reading above until G2 and G3 put the encodings to QEMU's units.Negative controls.
286536fb8with nothing else and run there:toyos-acpi2 failed of 29 (Range { at: 72, base: 4294967295, last: 4294967295 }where the table must open),toyos-smmu1 failed of 23 (Some(..)whereNoneis owed), exits 101 and 101. The patch and the log are in the comment below; the step-log directory's copies went when that directory was deleted. The same three tests are green at this head.6193b7376, built, run and reverted: ten red (r3-mutations.log,EXIT=0). The patches, results and the tests each turned red are in the comment below.iort-own-past-acceptedandiort-own-past-by-onedrop theOwnMappingcheck or make it>;iort-shared-uncheckeddrops the call;iort-shared-any-unitcounts a mapping to any node;iort-shared-counts-itselfandiort-shared-by-index-alonecount the requester's own mapping, or skip indexby.1of every node;iort-shared-single-spansandiort-shared-span-exclusiveread a single mapping's span and drop the last ID;iort-shared-array-floorandiort-shared-array-enddrop either half of the placement check of an undecoded node's ID array.f8022b7e2(39toyos-acpi; 108 undertoyos-smmu's tests, 10 of them mutatingtoyos-bootmap/src/aarch64.rs; 3toyos-phys; 80toyos-its). Every file a round 1 mutation lived in changed, so each was written again against the new text, and the fourmadt-*went with their code. The patches and results are in five comments below. None stayed green. They were not run again at this head.no_corruption_of_a_published_iort_panics_or_hangs_the_decoderputs seven values in every byte of both captured IORTs and declares every shorter length, then asks for 512 requesters each time.probe,event, the queues' arithmetic andIts::collectionsare total over their inputs and are fed extreme register values.Gates, at 6193b73
Each is the command's own exit code, run in sequence from the committed tree by one script;
git status --porcelain --ignore-submodules=noneprinted nothing before the first and after the last. The logs are in the brief's step-log directory under the names given.6193b7376isbf56c79ef(this round's change) withorigin/mainat558283168merged in; the merge was clean andgit diff origin/main HEAD -- toyos-acpi/src/madt.rsprints nothing.cargo test -p toyos-acpi -p toyos-smmu -p toyos-its -p toyos-physr3-suites.log:toyos-acpi104 tests (31 of them intests/iort.rs),toyos-smmu27,toyos-its21,toyos-phys2git apply --check, apply,cargo test -p toyos-acpi --no-run,cargo test -p toyos-acpi,git apply -Rr3-mutations.log: 10 mutations, 10 redcargo run -- --clippyr3-clippy.log: "24 invocations clean"cargo test --libr3-buildsystem.log: 340 passed, 15 ignoredcargo run -- --ci hostr3-ci-host.log: "Host: 78 step(s), all green", theiorttests, bothencodingssuites andphysin it; its 114FAILEDlines all fall inside the harness's own[ci] controlblocks, 50 of which report "verdict(s) reached"cargo run -- --build-onlyr3-build-only.logThe host's load when each started, from
uptime: 38, 39, 42, 36, 37 and 25 (one-minute averages; the machine is shared). A first run of the same script was stopped by me during--ci hostwhen the directory its logs were written to was deleted by something outside this branch's work; every result above is from the second, complete run.No guest test is added, changed or reached.
git diff origin/main -- toyos-acpi/src/madt.rsis empty, so the MADT walk the kernel boots through ismain's. What the kernel and the loader link that differs frommain:toyos-acpigains a module nothing inkernel/calls, andtoyos-bootmap'sPXNgainspub. Neither is a line a boot runs.--metalwas not run in any form.What I am unsure of
probeis judged on crafted registers only. What QEMU's units report (IDR0.STALL_MODEL,IDR0.COHACC,IDR1.SIDSIZE,IDR5.OAS,GITS_TYPER.PTA,HCCandCIL, theGITS_BASERtypes, whetherGICR_PROPBASER.IDbitsreads back as written) is G2's and G3's first measurement.Its::collectionsreads §5.2.2 andCCTtogether. §5.3.1 gives the total asHCCplus the table's entries, andGITS_TYPER.CCTsays the table's alone where it is clear; I took the smaller where they differ.pypdf's text visitor, which reports none for it.OwnMapping { index: 0, count: 0 }, where round 2 opened it: by E.d's wording its index holds and names nothing. A unit whose PRI GSIV is zero only because it has no PRI would be one; it is not onvirt. The node-revision test's SMMUv3 fixture was one, and is given four GSIVs this round so that it tests revisions alone.6193b7376. This round changesiort.rs'sroute,hitsandcheck, which some of the 39toyos-acpiones touch.toyos-itsbesidekernel/gicv3'stoyos-gicv3, and the stage 1 bits beside the kernel's: recorded in the issue named above, for the stages that touch those files.Fence
toyos-acpi/src/iort.rs,src/lib.rsandtests/iort.rswith the six fixtures;toyos-smmu,toyos-itsandtoyos-phys; rootCargo.toml's members andCargo.lock;toyos-bootmap/src/aarch64.rsby onepub; sixCOMMITTED_FILESrows insrc/licence.rs, becausesrc/sourcegate.rsreds on a committed binary without one; one issue file.NOTICEis unchanged: the fixtures are this project's capture of firmware output, as the q35 tables are.Size
git diff --shortstat origin/main...HEAD: 30 files changed, 3852 insertions(+), 2 deletions(-). Production Rust +1845 −2 (the IORT decoder 453,toyos-acpi/src/lib.rs4,toyos-smmu793,toyos-its521,toyos-phys33, six licence rows 40, one word intoyos-bootmap); tests +1856; manifests, lockfile,SOURCEand the issue +151; six fixtures, 1396 bytes.Against round 1, production is +141: the MADT's controllers went (−83) and the two
Physbecame one, while each of the review's findings that asked for a type or a check added lines — the own-mapping index (toyos-acpi+33), the output-size checks and the two queue types (toyos-smmu+72), andEvent,Collection,Layout/SpaceandBacking(toyos-its+90). None has a consumer before G2 and G3. Round 3 adds 37 lines of production, all iniort.rs, for the two refusals.All of it is new decoding and encoding with no predecessor to delete;
kernel/src/arch/aarch64/iommu_unit.rs's stub goes in G2.🤖 Generated with Claude Code
https://claude.ai/code/session_017cSFvbD35xJ2kGANVdm23C